From bd84e893b6898005c4435d4d0d38dcd6c731da66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Lafr=C3=A9choux?= Date: Tue, 3 Jun 2025 10:18:40 +0200 Subject: [PATCH] Processes: use start_dt timezone --- src/bemserver_core/process/energy_power.py | 6 ++ src/bemserver_core/process/forward_fill.py | 3 + tests/process/test_energy_power.py | 88 ++++++++++++++++++++++ tests/process/test_forward_fill.py | 28 +++++++ 4 files changed, 125 insertions(+) diff --git a/src/bemserver_core/process/energy_power.py b/src/bemserver_core/process/energy_power.py index fab8586f..bc2b5b32 100644 --- a/src/bemserver_core/process/energy_power.py +++ b/src/bemserver_core/process/energy_power.py @@ -58,6 +58,8 @@ def energy2power( convert_to, ): """Convert energy to power""" + timezone = start_dt.tzinfo + end_dt = end_dt.astimezone(timezone) interval = energy_ts.get_property_value("Interval") if interval is None: @@ -71,6 +73,7 @@ def energy2power( end_dt, (energy_ts,), data_state, + timezone=str(timezone), )[energy_ts.id] # Power = Energy / Time @@ -93,6 +96,8 @@ def energyindex2power( convert_to, ): """Convert energy index to power""" + timezone = start_dt.tzinfo + end_dt = end_dt.astimezone(timezone) # Get energy index values index_s = tsdio.get_timeseries_data( @@ -100,6 +105,7 @@ def energyindex2power( end_dt, (index_ts,), data_state, + timezone=str(timezone), )[index_ts.id] # Compute energy as diff, with a 0 min for index rollover or meter change diff --git a/src/bemserver_core/process/forward_fill.py b/src/bemserver_core/process/forward_fill.py index 5dcb13a3..4dcc8931 100644 --- a/src/bemserver_core/process/forward_fill.py +++ b/src/bemserver_core/process/forward_fill.py @@ -18,6 +18,8 @@ def ffill( bucket_width_unit, ): """Forward fill process""" + timezone = start_dt.tzinfo + end_dt = end_dt.astimezone(timezone) # Define expected index start_dt = ceil(start_dt, bucket_width_unit, bucket_width_value) @@ -41,6 +43,7 @@ def ffill( end_dt, timeseries, data_state, + timezone=str(timezone), ) # For each TS, set last value before time interval as first value for interval diff --git a/tests/process/test_energy_power.py b/tests/process/test_energy_power.py index 47b460ab..c7169fea 100644 --- a/tests/process/test_energy_power.py +++ b/tests/process/test_energy_power.py @@ -1,6 +1,7 @@ """Energy <=> Power conversions tests""" import datetime as dt +from zoneinfo import ZoneInfo import pytest @@ -153,6 +154,35 @@ def test_power2energy_process(self, users, timeseries): ) assert_series_equal(data_s, expected_data_s) + # Check result is in start_dt timezone + data_s = power2energy( + start_dt.astimezone(ZoneInfo("Europe/Paris")), + h4_dt, + ts_0, + ds_1, + 1800, + "Wh", + ) + timestamps = sum( + [ + [ + dt.datetime( + 2020, 1, 1, hour, 0, tzinfo=dt.timezone.utc + ).astimezone(ZoneInfo("Europe/Paris")), + dt.datetime( + 2020, 1, 1, hour, 30, tzinfo=dt.timezone.utc + ).astimezone(ZoneInfo("Europe/Paris")), + ] + for hour in (0, 1, 2, 3) + ], + [], + ) + expected_data_s = pd.Series( + [0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.5, 0.5], + index=pd.DatetimeIndex(timestamps, name="timestamp", freq="1800s"), + ) + assert_series_equal(data_s, expected_data_s) + with pytest.raises(BEMServerCoreUndefinedUnitError): data_s = power2energy(start_dt, h4_dt, ts_0, ds_1, 3600, "dummy") @@ -283,6 +313,22 @@ def test_energy2power_process(self, users, timeseries): ): data_s = energy2power(start_dt, end_dt, ts_4, ds_1, "W") + # Check result is in start_dt timezone + data_s = energy2power( + start_dt.astimezone(ZoneInfo("Europe/Paris")), h4_dt, ts_0, ds_1, "W" + ) + timestamps = [ + dt.datetime(2020, 1, 1, hour, 0, tzinfo=dt.timezone.utc).astimezone( + ZoneInfo("Europe/Paris") + ) + for hour in (0, 1, 2, 3) + ] + expected_data_s = pd.Series( + [0.0, 1.0, 0.0, 1.0], + index=pd.DatetimeIndex(timestamps, name="timestamp"), + ) + assert_series_equal(data_s, expected_data_s) + with pytest.raises(BEMServerCoreUndefinedUnitError): data_s = energy2power(start_dt, end_dt, ts_0, ds_1, "dummy") @@ -410,6 +456,27 @@ def test_energyindex2power_process(self, users, timeseries): ) assert_series_equal(data_s, expected_data_s) + # Check result is in start_dt timezone + data_s = energyindex2power( + start_dt.astimezone(ZoneInfo("Europe/Paris")), + h6_dt, + ts_0, + ds_1, + 3600, + "W", + ) + timestamps = [ + dt.datetime(2020, 1, 1, hour, 0, tzinfo=dt.timezone.utc).astimezone( + ZoneInfo("Europe/Paris") + ) + for hour in (0, 1, 2, 3, 4, 5) + ] + expected_data_s = pd.Series( + [1.0, 3.0, 5.0, 7.0, 9.0, np.nan], + index=pd.DatetimeIndex(timestamps, name="timestamp", freq="h"), + ) + assert_series_equal(data_s, expected_data_s) + with pytest.raises(BEMServerCoreUndefinedUnitError): data_s = energyindex2power(start_dt, end_dt, ts_0, ds_1, 3600, "dummy") @@ -537,6 +604,27 @@ def test_energyindex2energy_process(self, users, timeseries): ) assert_series_equal(data_s, expected_data_s) + # Check result is in start_dt timezone + data_s = energyindex2energy( + start_dt.astimezone(ZoneInfo("Europe/Paris")), + h6_dt, + ts_0, + ds_1, + 3600, + "Wh", + ) + timestamps = [ + dt.datetime(2020, 1, 1, hour, 0, tzinfo=dt.timezone.utc).astimezone( + ZoneInfo("Europe/Paris") + ) + for hour in (0, 1, 2, 3, 4, 5) + ] + expected_data_s = pd.Series( + [1.0, 3.0, 5.0, 7.0, 9.0, np.nan], + index=pd.DatetimeIndex(timestamps, name="timestamp", freq="h"), + ) + assert_series_equal(data_s, expected_data_s) + with pytest.raises(BEMServerCoreUndefinedUnitError): data_s = energyindex2energy(start_dt, end_dt, ts_0, ds_1, 3600, "dummy") diff --git a/tests/process/test_forward_fill.py b/tests/process/test_forward_fill.py index 3db4de2c..daf6f6b3 100644 --- a/tests/process/test_forward_fill.py +++ b/tests/process/test_forward_fill.py @@ -1,6 +1,7 @@ """Forward fill tests""" import datetime as dt +from zoneinfo import ZoneInfo import pytest @@ -113,3 +114,30 @@ def test_ffill_process(self, users, timeseries): ) expected_data_df.columns = [ts_3.id, ts_2.id, ts_2.id, ts_0.id] assert_frame_equal(data_df, expected_data_df) + + # Check result is in start_dt timezone + ts_l = (ts_0, ts_1, ts_2, ts_3) + + data_df = ffill( + h4_dt.astimezone(ZoneInfo("Europe/Paris")), + end_dt, + ts_l, + ds_1, + 2, + "hour", + ) + + timestamps = [ + dt.datetime(2020, 1, 1, hour, 0, tzinfo=ZoneInfo("Europe/Paris")) + for hour in (6, 7, 8, 10, 12) + ] + expected_data_df = pd.DataFrame( + { + ts_0.id: [1.0, np.nan, 1.0, 1.0, 1.0], + ts_1.id: [0.0, 6.0, 6.0, 9.0, 9.0], + ts_2.id: [np.nan, 42.0, 42.0, 42.0, 42.0], + ts_3.id: [np.nan, np.nan, np.nan, np.nan, np.nan], + }, + index=pd.DatetimeIndex(timestamps, name="timestamp"), + ) + assert_frame_equal(data_df, expected_data_df)