|
1 | 1 | #
|
2 |
| -# Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending |
| 2 | +# Copyright (c) 2016-2024 Deephaven Data Labs and Patent Pending |
3 | 3 | #
|
4 | 4 |
|
5 | 5 | """ This module defines functions for handling Deephaven date/time data. """
|
6 | 6 |
|
7 | 7 | from __future__ import annotations
|
8 | 8 |
|
9 | 9 | import datetime
|
| 10 | +import zoneinfo |
| 11 | +import pytz |
10 | 12 | from typing import Union, Optional, Literal
|
11 | 13 |
|
12 | 14 | import jpy
|
@@ -165,45 +167,59 @@ def time_zone_alias_rm(alias: str) -> bool:
|
165 | 167 |
|
166 | 168 | # region Conversions: Python To Java
|
167 | 169 |
|
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: |
169 | 171 | """
|
170 | 172 | Converts a Python time zone to a Java TimeZone.
|
171 | 173 |
|
172 | 174 | Args:
|
173 | 175 | tzi: time zone info
|
174 |
| - offset: UTC offset |
175 | 176 |
|
176 | 177 | Returns:
|
177 | 178 | Java TimeZone
|
178 | 179 | """
|
| 180 | + |
179 | 181 | if not tzi:
|
180 | 182 | return None
|
181 | 183 |
|
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) |
187 | 193 |
|
188 |
| - # Try to get the time zone from the UTC offset |
| 194 | + # Handle constant UTC offset time zones (datetime.timezone) |
189 | 195 |
|
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) |
192 | 198 |
|
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") |
195 | 201 |
|
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 |
197 | 215 |
|
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}") |
203 | 219 |
|
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}") |
207 | 223 |
|
208 | 224 |
|
209 | 225 | 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
|
232 | 248 | elif isinstance(tz, str):
|
233 | 249 | return _JDateTimeUtils.parseTimeZone(tz)
|
234 | 250 | 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) |
236 | 252 | elif isinstance(tz, datetime.datetime):
|
237 | 253 | 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) |
239 | 255 |
|
240 | 256 | if not rst:
|
241 | 257 | raise ValueError("datetime is not time zone aware")
|
|
0 commit comments