Skip to content

Commit 4eafd4e

Browse files
authored
fix: Fix DateTime according to DST (#70)
1 parent 6f2e14e commit 4eafd4e

File tree

3 files changed

+48
-15
lines changed

3 files changed

+48
-15
lines changed

ims_envista/commons.py

+6
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ def _verify_response_or_raise(response: ClientResponse) -> None:
6666
raise ImsEnvistaApiClientAuthenticationError(
6767
msg,
6868
)
69+
content_type = response.headers.get("Content-Type")
70+
if content_type and "application/json" not in content_type:
71+
msg = f"Invalid response from IMS - bad Content-Type: {content_type}"
72+
raise ImsEnvistaApiClientError(
73+
msg,
74+
)
6975
response.raise_for_status()
7076

7177

ims_envista/meteo_data.py

+22-3
Original file line numberDiff line numberDiff line change
@@ -151,12 +151,31 @@ def __repr__(self) -> str:
151151

152152
tz = pytz.timezone("Asia/Jerusalem")
153153

154+
155+
def _fix_datetime_offset(dt):
156+
dt = dt.replace(tzinfo=None)
157+
dt = tz.localize(dt)
158+
159+
# Get the UTC offset in seconds
160+
offset_seconds = dt.utcoffset().total_seconds()
161+
162+
# Create a fixed timezone with the same offset and name
163+
fixed_timezone = datetime.timezone(datetime.timedelta(seconds=offset_seconds), dt.tzname())
164+
165+
# Replace the pytz tzinfo with the fixed timezone
166+
dt = dt.replace(tzinfo=fixed_timezone)
167+
168+
is_dst = dt.dst() != datetime.timedelta(0)
169+
if is_dst:
170+
dt = dt + datetime.timedelta(hours=1)
171+
172+
return dt,is_dst
173+
174+
154175
def meteo_data_from_json(station_id: int, data: dict) -> MeteorologicalData:
155176
"""Create a MeteorologicalData object from a JSON object."""
156-
is_dst = bool(time.localtime(time.time()).tm_isdst)
157-
158177
dt = datetime.datetime.fromisoformat(data[API_DATETIME])
159-
dt.replace(tzinfo=tz)
178+
dt, is_dst = _fix_datetime_offset(dt)
160179

161180
channel_value_dict = {}
162181
for channel_value in data[API_CHANNELS]:

tests/unit/test_ims_envista.py

+20-12
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from datetime import date, datetime, timedelta
66
from zoneinfo import ZoneInfo
77

8+
import pytz
89
from aiohttp import ClientSession
910

1011
from ims_envista import IMSEnvista
@@ -27,6 +28,7 @@ async def asyncSetUp(self) -> None:
2728

2829
# Initialize the session in an async context
2930
self.session = ClientSession()
31+
self.tz = pytz.timezone("Asia/Jerusalem")
3032
self.ims = IMSEnvista(self.token, session=self.session)
3133

3234
async def asyncTearDown(self) -> None:
@@ -117,35 +119,38 @@ async def test_get_earliest_station_data_with_channel(self) -> None:
117119
async def test_get_station_data_from_date(self) -> None:
118120
"""Test get_station_data_from_date endpoint."""
119121
station_data = await self.ims.get_station_data_from_date(
120-
self.station_id, datetime.now(tz=ZoneInfo("Asia/Jerusalem"))
122+
self.station_id, self.tz.localize(datetime.now())
121123
)
122124

123125
assert station_data is not None
124126
assert station_data.station_id == self.station_id
125127
assert station_data.data is not None
126128
assert len(station_data.data) > 0
127129
for station_reading in station_data.data:
128-
assert station_reading.datetime.date() == datetime.now(tz=ZoneInfo("Asia/Jerusalem")).date()
130+
assert station_reading.datetime.date() == self.tz.localize(datetime.now()).date()
129131

130132

131133
async def test_get_station_data_from_date_with_channel(self) -> None:
132134
"""Test get_station_data_from_date endpoint with channel."""
133135
station_data = await self.ims.get_station_data_from_date(
134-
self.station_id, datetime.now(tz=ZoneInfo("Asia/Jerusalem")), self.channel_id
136+
self.station_id, self.tz.localize(datetime.now()), self.channel_id
135137
)
136138

137139
assert station_data is not None
138140
assert station_data.station_id == self.station_id
139141
assert station_data.data is not None
140142
assert len(station_data.data) > 0
141143
for station_reading in station_data.data:
142-
assert station_reading.datetime.date() == datetime.now(tz=ZoneInfo("Asia/Jerusalem")).date()
144+
assert station_reading.datetime.date() == self.tz.localize(datetime.now()).date()
143145

144146

145147
async def test_get_station_data_by_date_range(self) -> None:
146148
"""Test get_station_data_by_date_range endpoint."""
147-
today = datetime.now(tz=ZoneInfo("Asia/Jerusalem"))
149+
today = self.tz.localize(datetime.now())
150+
today = today.replace(hour=0, minute=0, second=0, microsecond=0)
148151
yesterday = today - timedelta(days=1)
152+
# `hour=1` for DST fix cases
153+
today = today.replace(hour=2, minute=0, second=0, microsecond=0)
149154
station_data = await self.ims.get_station_data_by_date_range(
150155
self.station_id, from_date=yesterday, to_date=today
151156
)
@@ -156,14 +161,17 @@ async def test_get_station_data_by_date_range(self) -> None:
156161
assert len(station_data.data) > 0
157162
for station_reading in station_data.data:
158163
assert station_reading.datetime >= to_date_time(yesterday)
159-
assert station_reading.datetime < to_date_time(today)
164+
assert station_reading.datetime < today
160165
assert station_reading.td > 0
161166

162167

163168
async def test_get_station_data_by_date_range_with_channel(self) -> None:
164169
"""Test get_station_data_by_date_range endpoint with channel."""
165-
today = datetime.now(tz=ZoneInfo("Asia/Jerusalem"))
170+
today = self.tz.localize(datetime.now())
171+
today = today.replace(hour=0, minute=0, second=0, microsecond=0)
166172
yesterday = today - timedelta(days=1)
173+
# `hour=1` for DST fix cases
174+
today = today.replace(hour=2, minute=0, second=0, microsecond=0)
167175
station_data = await self.ims.get_station_data_by_date_range(
168176
self.station_id,
169177
from_date=yesterday,
@@ -177,14 +185,14 @@ async def test_get_station_data_by_date_range_with_channel(self) -> None:
177185
assert len(station_data.data) > 0
178186
for station_reading in station_data.data:
179187
assert station_reading.datetime >= to_date_time(yesterday)
180-
assert station_reading.datetime < to_date_time(today)
188+
assert station_reading.datetime < today
181189
assert station_reading.td > 0
182190

183191

184192
async def test_get_monthly_station_data(self) -> None:
185193
"""Test get_monthly_station_data endpoint."""
186-
year = datetime.now(tz=ZoneInfo("Asia/Jerusalem")).strftime("%Y")
187-
month = datetime.now(tz=ZoneInfo("Asia/Jerusalem")).strftime("%m")
194+
year = self.tz.localize(datetime.now()).strftime("%Y")
195+
month = self.tz.localize(datetime.now()).strftime("%m")
188196
station_data = await self.ims.get_monthly_station_data(
189197
self.station_id, month=month, year=year
190198
)
@@ -201,8 +209,8 @@ async def test_get_monthly_station_data(self) -> None:
201209

202210
async def test_get_monthly_station_data_with_channel(self) -> None:
203211
"""Test get_monthly_station_data endpoint with channel."""
204-
year = datetime.now(tz=ZoneInfo("Asia/Jerusalem")).strftime("%Y")
205-
month = datetime.now(tz=ZoneInfo("Asia/Jerusalem")).strftime("%m")
212+
year = self.tz.localize(datetime.now()).strftime("%Y")
213+
month = self.tz.localize(datetime.now()).strftime("%m")
206214
station_data = await self.ims.get_monthly_station_data(
207215
self.station_id, channel_id=self.channel_id, month=month, year=year
208216
)

0 commit comments

Comments
 (0)