3737use DateTimeImmutable ;
3838use DateTimeInterface ;
3939use DateTimeZone ;
40+ use DBmysql ;
4041use GLPIKey ;
4142use GlpiPlugin \Carbon \CarbonIntensity ;
4243use GlpiPlugin \Carbon \DataSource \CarbonIntensity \AbortException ;
@@ -269,6 +270,7 @@ public function fetchDay(DateTimeImmutable $day, Source_Zone $source_zone): arra
269270
270271 public function fetchRange (DateTimeImmutable $ start , DateTimeImmutable $ stop , Source_Zone $ source_zone ): array
271272 {
273+ $ this ->step = 60 ;
272274 $ is_free_plan = Config::getConfigurationValue ('electricitymap_fake_data ' ) ?? 0 ;
273275 $ dataset = $ is_free_plan ? 'fake ' : 'real ' ;
274276 $ zone = new Zone ();
@@ -277,7 +279,8 @@ public function fetchRange(DateTimeImmutable $start, DateTimeImmutable $stop, So
277279 $ cache_file = $ this ->getCacheFilename (
278280 $ base_path ,
279281 $ start ,
280- $ stop
282+ $ stop ,
283+ $ start ->getTimezone ()
281284 );
282285 // If cached file exists, use it
283286 if (file_exists ($ cache_file )) {
@@ -306,6 +309,7 @@ public function fetchRange(DateTimeImmutable $start, DateTimeImmutable $stop, So
306309 $ glpikey = new GLPIKey ();
307310 $ api_key = Config::getConfigurationValue ('electricitymap_api_key ' );
308311 $ api_key = $ glpikey ->decrypt ($ api_key );
312+ $ format = 'Y-m-d\+H:ip ' ;
309313 while ($ current_date < $ request_stop ) {
310314 $ stop = clone $ current_date ;
311315 $ stop ->add ($ step );
@@ -319,8 +323,8 @@ public function fetchRange(DateTimeImmutable $start, DateTimeImmutable $stop, So
319323 // ];
320324 $ url = $ this ->base_url . self ::PAST_URL ;
321325 $ url .= '?zone= ' . $ source_zone ->fields ['code ' ];
322- $ url .= '&start= ' . $ current_date ->format (' Y-m-d\+H:i ' );
323- $ url .= '&end= ' . $ stop ->format (' Y-m-d\+H:i ' );
326+ $ url .= '&start= ' . $ current_date ->format ($ format );
327+ $ url .= '&end= ' . $ stop ->format ($ format );
324328 $ url .= '&temporalGranularity= ' . 'hourly ' ;
325329 $ url .= '&emissionFactorType= ' . 'lifecycle ' ;
326330 $ response = $ this ->client ->request ('GET ' , $ url , [/*'query' => $params,*/ 'headers ' => ['auth-token ' => $ api_key ]]);
@@ -360,10 +364,13 @@ public function fetchRange(DateTimeImmutable $start, DateTimeImmutable $stop, So
360364
361365 protected function formatOutput (array $ response , int $ step ): array
362366 {
367+ // Convert string dates into datetime objects,
368+ // using timezone expressed as type Continent/City instead of offset
369+ // This is needed to detect later the switching to winter time
370+ $ response = $ this ->shiftToLocalTimezone ($ response );
363371 $ intensities = [];
364- $ timezone = new DateTimeZone ('UTC ' );
365- foreach ($ response ['history ' ] as $ record ) {
366- $ datetime = DateTime::createFromFormat ('Y-m-d\TH:i:s+ ' , $ record ['datetime ' ], $ timezone );
372+ foreach ($ response ['data ' ] as $ record ) {
373+ $ datetime = $ record ['datetime ' ];
367374 if (!$ datetime instanceof DateTimeInterface) {
368375 var_dump (DateTime::getLastErrors ());
369376 continue ;
@@ -379,18 +386,42 @@ protected function formatOutput(array $response, int $step): array
379386 return $ intensities ;
380387 }
381388
389+ /**
390+ * convert dates to the timezone of GLPI
391+ *
392+ * @param array $response
393+ * @return array array of records: ['date_heure' => string, 'taux_co2' => number, 'datetime' => DateTime]
394+ */
395+ protected function shiftToLocalTimezone (array $ response ): array
396+ {
397+ /** @var DBmysql $DB */
398+ global $ DB ;
399+
400+ $ shifted_response = [];
401+ $ local_timezone = new DateTimeZone ($ DB ->guessTimezone ());
402+ array_walk ($ response ['data ' ], function ($ item , $ key ) use (&$ shifted_response , $ local_timezone ) {
403+ $ shifted_date_object = DateTime::createFromFormat ('Y-m-d\TH:i:s.vp ' , $ item ['datetime ' ])
404+ ->setTimezone ($ local_timezone );
405+ $ shifted_date_string = $ shifted_date_object ->format ('Y-m-d H:i:sP ' );
406+ if (isset ($ shifted_response [$ shifted_date_string ]) && $ shifted_response ['carbonIntensity ' ] !== $ item ['carbonIntensity ' ]) {
407+ trigger_error ("Duplicate record with different carbon intensity detected. " );
408+ }
409+ $ item ['datetime ' ] = $ shifted_date_object ;
410+ $ shifted_response [$ shifted_date_string ] = $ item ;
411+ });
412+
413+ return ['zone ' => $ response ['zone ' ], 'data ' => $ shifted_response ];
414+ }
415+
382416 /**
383417 * Try to determine the data quality of record
384418 *
385419 * @param array $record
386- * @return int
420+ * @return int see AbstractTracked::DATA_QUALITY_* constants
387421 */
388422 protected function getDataQuality (array $ record ): int
389423 {
390- $ data_quality = 0 ;
391- if (!$ record ['isEstimated ' ]) {
392- $ data_quality = AbstractTracked::DATA_QUALITY_RAW_REAL_TIME_MEASUREMENT ;
393- }
424+ $ data_quality = $ record ['isEstimated ' ] ? AbstractTracked::DATA_QUALITY_ESTIMATED : AbstractTracked::DATA_QUALITY_RAW_REAL_TIME_MEASUREMENT ;
394425
395426 return $ data_quality ;
396427 }
0 commit comments