fix: honor Energy-Charts electricity price interval coverage (#1278)

* fix: honor Energy-Charts electricity price interval coverage

* test: make Energy-Charts coverage checks timezone-independent
This commit is contained in:
dr-dimitri
2026-09-05 15:50:43 +02:00
committed by GitHub
parent 940aa1021f
commit 9d816acbd9
2 changed files with 118 additions and 6 deletions
@@ -98,6 +98,25 @@ class ElecPriceEnergyCharts(ElecPriceProvider):
"""Return the unique identifier for the Energy-Charts provider."""
return "ElecPriceEnergyCharts"
def _has_complete_published_horizon(
self, *, now: pd.Timestamp, resolution_seconds: int
) -> bool:
"""Return whether stored source data covers all currently published intervals.
Energy-Charts timestamps identify interval starts. The actual coverage therefore ends one
source interval after ``highest_orig_datetime``. Before 14:00, prices through the end of
the current day are expected; from 14:00 onward, the following day is expected as well.
"""
if self.highest_orig_datetime is None:
return False
published_days = 1 if now.hour < 14 else 2
required_coverage_end = now.normalize() + pd.DateOffset(days=published_days)
coverage_end = pd.Timestamp(self.highest_orig_datetime) + pd.Timedelta(
seconds=resolution_seconds
)
return coverage_end >= required_coverage_end
@classmethod
def _validate_data(cls, json_str: Union[bytes, Any]) -> EnergyChartsElecPrice:
"""Validate Energy-Charts Electricity Price forecast data."""
@@ -211,11 +230,8 @@ class ElecPriceEnergyCharts(ElecPriceProvider):
The final mapped and processed data is inserted into the sequence as `ElecPriceDataRecord`.
"""
# New prices are available every day at 14:00
# Tomorrow's prices are available every day at 14:00.
now = pd.Timestamp.now(tz=self.config.general.timezone)
midnight = now.normalize()
hours_ahead = 23 if now.time() < pd.Timestamp("14:00").time() else 47
end = midnight + pd.Timedelta(hours=hours_ahead)
if not self.ems_start_datetime:
raise ValueError(f"Start DateTime not set: {self.ems_start_datetime}")
@@ -254,8 +270,10 @@ class ElecPriceEnergyCharts(ElecPriceProvider):
elif force_update:
# Use default start date in case of forced update
needs_update = True
elif end > self.highest_orig_datetime:
# We got enough history, but still not enough data to prediction end
elif not self._has_complete_published_horizon(
now=now, resolution_seconds=resolution_seconds
):
# We have enough history, but not every expected source interval.
start_datetime = gross_start_datetime
needs_update = True
else: