Skip to content

Commit

Permalink
Make python timezone conversions handle more cases.
Browse files Browse the repository at this point in the history
Resolves #4723
  • Loading branch information
chipkent committed Mar 13, 2024
1 parent 9fcaba7 commit 7e7e917
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 6 deletions.
51 changes: 47 additions & 4 deletions py/server/deephaven/time.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,46 @@ def time_zone_alias_rm(alias: str) -> bool:

# region Conversions: Python To Java

def _tzinfo_to_j_time_zone(tzi: datetime.tzinfo, offset: datetime.timedelta) -> TimeZone:
"""
Converts a Python time zone to a Java TimeZone.
Args:
tzi: time zone info
offset: UTC offset
Returns:
Java TimeZone
"""
if not tzi:
return None

# Try to get the time zone from the zone name
try:
return _JDateTimeUtils.parseTimeZone(str(tzi))
except Exception:
pass

# Try to get the time zone from the UTC offset

if not offset:
raise ValueError("Unable to determine the time zone UTC offset")

if offset.microseconds != 0 or offset.seconds%60 != 0:
raise ValueError(f"Unsupported time zone offset contains fractions of a minute: {offset}")

ts = offset.total_seconds()

if ts >= 0:
sign = "+"
else:
sign = "-"
ts = -ts

hours = int(ts / 3600)
minutes = int((ts % 3600) / 60)
return _JDateTimeUtils.parseTimeZone(f"UTC{sign}{hours:02d}:{minutes:02d}")


def to_j_time_zone(tz: Union[None, TimeZone, str, datetime.tzinfo, datetime.datetime, pandas.Timestamp]) -> \
Optional[TimeZone]:
Expand Down Expand Up @@ -192,12 +232,15 @@ def to_j_time_zone(tz: Union[None, TimeZone, str, datetime.tzinfo, datetime.date
elif isinstance(tz, str):
return _JDateTimeUtils.parseTimeZone(tz)
elif isinstance(tz, datetime.tzinfo):
return _JDateTimeUtils.parseTimeZone(str(tz))
return _tzinfo_to_j_time_zone(tz, tz.utcoffset(None) if tz else None)
elif isinstance(tz, datetime.datetime):
if not tz.tzname():
return _JDateTimeUtils.parseTimeZone(tz.astimezone().tzname())
tzi = tz.tzinfo
rst = _tzinfo_to_j_time_zone(tzi, tzi.utcoffset(tz) if tzi else None)

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

return _JDateTimeUtils.parseTimeZone(tz.tzname())
return rst
else:
raise TypeError("Unsupported conversion: " + str(type(tz)) + " -> TimeZone")
except TypeError as e:
Expand Down
18 changes: 16 additions & 2 deletions py/server/tests/test_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,9 @@ def test_to_j_time_zone(self):
self.assertEqual(str(tz), "UTC")

pytz = datetime.datetime.now()
tz = to_j_time_zone(pytz)
self.assertEqual(str(tz), "UTC")
with self.assertRaises(DHError):
tz = to_j_time_zone(pytz)
self.fail("Expected DHError")

pytz = datetime.datetime.now().astimezone()
tz = to_j_time_zone(pytz)
Expand All @@ -93,6 +94,19 @@ def test_to_j_time_zone(self):
tz2 = to_j_time_zone(tz1)
self.assertEqual(tz1, tz2)

ts = pd.Timestamp("2022-07-07", tz="America/New_York")
self.assertEqual(to_j_time_zone(ts), to_j_time_zone("America/New_York"))

dttz = datetime.timezone(offset=datetime.timedelta(hours=5), name="XYZ")
dt = datetime.datetime(2022, 7, 7, 14, 21, 17, 123456, tzinfo=dttz)
self.assertEqual(to_j_time_zone(dttz), to_j_time_zone("UTC+5"))
self.assertEqual(to_j_time_zone(dt), to_j_time_zone("UTC+5"))

dttz = datetime.timezone(offset=-datetime.timedelta(hours=5), name="XYZ")
dt = datetime.datetime(2022, 7, 7, 14, 21, 17, 123456, tzinfo=dttz)
self.assertEqual(to_j_time_zone(dttz), to_j_time_zone("UTC-5"))
self.assertEqual(to_j_time_zone(dt), to_j_time_zone("UTC-5"))

with self.assertRaises(TypeError):
to_j_time_zone(False)
self.fail("Expected TypeError")
Expand Down

0 comments on commit 7e7e917

Please sign in to comment.