@@ -3,6 +3,14 @@ from datetime import (
33 timezone,
44)
55
6+ try :
7+ # py39+
8+ import zoneinfo
9+ from zoneinfo import ZoneInfo
10+ except ImportError :
11+ zoneinfo = None
12+ ZoneInfo = None
13+
614from cpython.datetime cimport (
715 datetime,
816 timedelta,
@@ -42,18 +50,43 @@ cdef tzinfo utc_stdlib = timezone.utc
4250cdef tzinfo utc_pytz = UTC
4351cdef tzinfo utc_dateutil_str = dateutil_gettz(" UTC" ) # NB: *not* the same as tzutc()
4452
53+ cdef tzinfo utc_zoneinfo = None
54+
4555
4656# ----------------------------------------------------------------------
4757
58+ cdef inline bint is_utc_zoneinfo(tzinfo tz):
59+ # Workaround for cases with missing tzdata
60+ # https://github.com/pandas-dev/pandas/pull/46425#discussion_r830633025
61+ if tz is None or zoneinfo is None :
62+ return False
63+
64+ global utc_zoneinfo
65+ if utc_zoneinfo is None :
66+ try :
67+ utc_zoneinfo = ZoneInfo(" UTC" )
68+ except zoneinfo.ZoneInfoNotFoundError:
69+ return False
70+
71+ return tz is utc_zoneinfo
72+
73+
4874cpdef inline bint is_utc(tzinfo tz):
4975 return (
5076 tz is utc_pytz
5177 or tz is utc_stdlib
5278 or isinstance (tz, _dateutil_tzutc)
5379 or tz is utc_dateutil_str
80+ or is_utc_zoneinfo(tz)
5481 )
5582
5683
84+ cdef inline bint is_zoneinfo(tzinfo tz):
85+ if ZoneInfo is None :
86+ return False
87+ return isinstance (tz, ZoneInfo)
88+
89+
5790cdef inline bint is_tzlocal(tzinfo tz):
5891 return isinstance (tz, _dateutil_tzlocal)
5992
@@ -210,6 +243,8 @@ cdef inline bint is_fixed_offset(tzinfo tz):
210243 return 1
211244 else :
212245 return 0
246+ elif is_zoneinfo(tz):
247+ return 0
213248 # This also implicitly accepts datetime.timezone objects which are
214249 # considered fixed
215250 return 1
@@ -264,6 +299,8 @@ cdef object get_dst_info(tzinfo tz):
264299 # e.g. pytz.FixedOffset, matplotlib.dates._UTC,
265300 # psycopg2.tz.FixedOffsetTimezone
266301 num = int (get_utcoffset(tz, None ).total_seconds()) * 1 _000_000_000
302+ # If we have e.g. ZoneInfo here, the get_utcoffset call will return None,
303+ # so the total_seconds() call will raise AttributeError.
267304 return (np.array([NPY_NAT + 1 ], dtype = np.int64),
268305 np.array([num], dtype = np.int64),
269306 " unknown" )
@@ -291,13 +328,13 @@ cdef object get_dst_info(tzinfo tz):
291328 # deltas
292329 deltas = np.array([v.offset for v in (
293330 tz._ttinfo_before,) + tz._trans_idx], dtype = ' i8' )
294- deltas *= 1000000000
331+ deltas *= 1 _000_000_000
295332 typ = ' dateutil'
296333
297334 elif is_fixed_offset(tz):
298335 trans = np.array([NPY_NAT + 1 ], dtype = np.int64)
299336 deltas = np.array([tz._ttinfo_std.offset],
300- dtype = ' i8' ) * 1000000000
337+ dtype = ' i8' ) * 1 _000_000_000
301338 typ = ' fixed'
302339 else :
303340 # 2018-07-12 this is not reached in the tests, and this case
0 commit comments