Skip to content

Commit bc3cc29

Browse files
committed
Responding to review. More careful support for time zone types.
1 parent 4cf2658 commit bc3cc29

File tree

2 files changed

+47
-25
lines changed

2 files changed

+47
-25
lines changed

py/server/deephaven/time.py

+40-24
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
#
2-
# Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending
2+
# Copyright (c) 2016-2024 Deephaven Data Labs and Patent Pending
33
#
44

55
""" This module defines functions for handling Deephaven date/time data. """
66

77
from __future__ import annotations
88

99
import datetime
10+
import zoneinfo
11+
import pytz
1012
from typing import Union, Optional, Literal
1113

1214
import jpy
@@ -165,45 +167,59 @@ def time_zone_alias_rm(alias: str) -> bool:
165167

166168
# region Conversions: Python To Java
167169

168-
def _tzinfo_to_j_time_zone(tzi: datetime.tzinfo, offset: datetime.timedelta) -> TimeZone:
170+
def _tzinfo_to_j_time_zone(tzi: datetime.tzinfo) -> TimeZone:
169171
"""
170172
Converts a Python time zone to a Java TimeZone.
171173
172174
Args:
173175
tzi: time zone info
174-
offset: UTC offset
175176
176177
Returns:
177178
Java TimeZone
178179
"""
180+
179181
if not tzi:
180182
return None
181183

182-
# Try to get the time zone from the zone name
183-
try:
184-
return _JDateTimeUtils.parseTimeZone(str(tzi))
185-
except Exception:
186-
pass
184+
# Handle pytz time zones
185+
186+
if isinstance(tzi, pytz.tzinfo.BaseTzInfo):
187+
return _JDateTimeUtils.parseTimeZone(tzi.zone)
188+
189+
# Handle zoneinfo time zones
190+
191+
if isinstance(tzi, zoneinfo.ZoneInfo):
192+
return _JDateTimeUtils.parseTimeZone(tzi.key)
187193

188-
# Try to get the time zone from the UTC offset
194+
# Handle constant UTC offset time zones (datetime.timezone)
189195

190-
if not offset:
191-
raise ValueError("Unable to determine the time zone UTC offset")
196+
if isinstance(tzi, datetime.timezone):
197+
offset = tzi.utcoffset(None)
192198

193-
if offset.microseconds != 0 or offset.seconds%60 != 0:
194-
raise ValueError(f"Unsupported time zone offset contains fractions of a minute: {offset}")
199+
if offset is None:
200+
raise ValueError("Unable to determine the time zone UTC offset")
195201

196-
ts = offset.total_seconds()
202+
if not offset:
203+
return _JDateTimeUtils.parseTimeZone("UTC")
204+
205+
if offset.microseconds != 0 or offset.seconds%60 != 0:
206+
raise ValueError(f"Unsupported time zone offset contains fractions of a minute: {offset}")
207+
208+
ts = offset.total_seconds()
209+
210+
if ts >= 0:
211+
sign = "+"
212+
else:
213+
sign = "-"
214+
ts = -ts
197215

198-
if ts >= 0:
199-
sign = "+"
200-
else:
201-
sign = "-"
202-
ts = -ts
216+
hours = int(ts / 3600)
217+
minutes = int((ts % 3600) / 60)
218+
return _JDateTimeUtils.parseTimeZone(f"UTC{sign}{hours:02d}:{minutes:02d}")
203219

204-
hours = int(ts / 3600)
205-
minutes = int((ts % 3600) / 60)
206-
return _JDateTimeUtils.parseTimeZone(f"UTC{sign}{hours:02d}:{minutes:02d}")
220+
details = "\n\t".join([f"type={type(tzi).mro()}"] +
221+
[f"obj.{attr}={getattr(tzi, attr)}" for attr in dir(tzi) if not attr.startswith("_")])
222+
raise TypeError(f"Unsupported conversion: {str(type(tzi))} -> TimeZone\n\tDetails:\n\t{details}")
207223

208224

209225
def to_j_time_zone(tz: Union[None, TimeZone, str, datetime.tzinfo, datetime.datetime, pandas.Timestamp]) -> \
@@ -232,10 +248,10 @@ def to_j_time_zone(tz: Union[None, TimeZone, str, datetime.tzinfo, datetime.date
232248
elif isinstance(tz, str):
233249
return _JDateTimeUtils.parseTimeZone(tz)
234250
elif isinstance(tz, datetime.tzinfo):
235-
return _tzinfo_to_j_time_zone(tz, tz.utcoffset(None) if tz else None)
251+
return _tzinfo_to_j_time_zone(tz)
236252
elif isinstance(tz, datetime.datetime):
237253
tzi = tz.tzinfo
238-
rst = _tzinfo_to_j_time_zone(tzi, tzi.utcoffset(tz) if tzi else None)
254+
rst = _tzinfo_to_j_time_zone(tzi)
239255

240256
if not rst:
241257
raise ValueError("datetime is not time zone aware")

py/server/tests/test_time.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
#
2-
# Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending
2+
# Copyright (c) 2016-2024 Deephaven Data Labs and Patent Pending
33
#
44

55
import unittest
66
from time import sleep
77
import datetime
8+
import zoneinfo
89
import pandas as pd
910
import numpy as np
1011

@@ -118,6 +119,11 @@ def test_to_j_time_zone(self):
118119
to_j_time_zone(dt)
119120
self.fail("Expected DHError")
120121

122+
dttz = zoneinfo.ZoneInfo("America/New_York")
123+
dt = datetime.datetime(2022, 7, 7, 14, 21, 17, 123456, tzinfo=dttz)
124+
self.assertEqual(to_j_time_zone(dttz), to_j_time_zone("America/New_York"))
125+
self.assertEqual(to_j_time_zone(dt), to_j_time_zone("America/New_York"))
126+
121127
with self.assertRaises(TypeError):
122128
to_j_time_zone(False)
123129
self.fail("Expected TypeError")

0 commit comments

Comments
 (0)