Skip to content

Commit

Permalink
Responding to review. More careful support for time zone types.
Browse files Browse the repository at this point in the history
  • Loading branch information
chipkent committed Mar 15, 2024
1 parent 4cf2658 commit bc3cc29
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 25 deletions.
64 changes: 40 additions & 24 deletions py/server/deephaven/time.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
#
# Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending
# Copyright (c) 2016-2024 Deephaven Data Labs and Patent Pending
#

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

from __future__ import annotations

import datetime
import zoneinfo
import pytz
from typing import Union, Optional, Literal

import jpy
Expand Down Expand Up @@ -165,45 +167,59 @@ 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:
def _tzinfo_to_j_time_zone(tzi: datetime.tzinfo) -> 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
# Handle pytz time zones

if isinstance(tzi, pytz.tzinfo.BaseTzInfo):
return _JDateTimeUtils.parseTimeZone(tzi.zone)

# Handle zoneinfo time zones

if isinstance(tzi, zoneinfo.ZoneInfo):
return _JDateTimeUtils.parseTimeZone(tzi.key)

# Try to get the time zone from the UTC offset
# Handle constant UTC offset time zones (datetime.timezone)

if not offset:
raise ValueError("Unable to determine the time zone UTC offset")
if isinstance(tzi, datetime.timezone):
offset = tzi.utcoffset(None)

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

ts = offset.total_seconds()
if not offset:
return _JDateTimeUtils.parseTimeZone("UTC")

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

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}")

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


def to_j_time_zone(tz: Union[None, TimeZone, str, datetime.tzinfo, datetime.datetime, pandas.Timestamp]) -> \
Expand Down Expand Up @@ -232,10 +248,10 @@ 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 _tzinfo_to_j_time_zone(tz, tz.utcoffset(None) if tz else None)
return _tzinfo_to_j_time_zone(tz)
elif isinstance(tz, datetime.datetime):
tzi = tz.tzinfo
rst = _tzinfo_to_j_time_zone(tzi, tzi.utcoffset(tz) if tzi else None)
rst = _tzinfo_to_j_time_zone(tzi)

if not rst:
raise ValueError("datetime is not time zone aware")
Expand Down
8 changes: 7 additions & 1 deletion py/server/tests/test_time.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#
# Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending
# Copyright (c) 2016-2024 Deephaven Data Labs and Patent Pending
#

import unittest
from time import sleep
import datetime
import zoneinfo
import pandas as pd
import numpy as np

Expand Down Expand Up @@ -118,6 +119,11 @@ def test_to_j_time_zone(self):
to_j_time_zone(dt)
self.fail("Expected DHError")

dttz = zoneinfo.ZoneInfo("America/New_York")
dt = datetime.datetime(2022, 7, 7, 14, 21, 17, 123456, tzinfo=dttz)
self.assertEqual(to_j_time_zone(dttz), to_j_time_zone("America/New_York"))
self.assertEqual(to_j_time_zone(dt), to_j_time_zone("America/New_York"))

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

0 comments on commit bc3cc29

Please sign in to comment.