@@ -3,6 +3,14 @@ from datetime import (
3
3
timezone,
4
4
)
5
5
6
+ try :
7
+ # py39+
8
+ import zoneinfo
9
+ from zoneinfo import ZoneInfo
10
+ except ImportError :
11
+ zoneinfo = None
12
+ ZoneInfo = None
13
+
6
14
from cpython.datetime cimport (
7
15
datetime,
8
16
timedelta,
@@ -42,18 +50,43 @@ cdef tzinfo utc_stdlib = timezone.utc
42
50
cdef tzinfo utc_pytz = UTC
43
51
cdef tzinfo utc_dateutil_str = dateutil_gettz(" UTC" ) # NB: *not* the same as tzutc()
44
52
53
+ cdef tzinfo utc_zoneinfo = None
54
+
45
55
46
56
# ----------------------------------------------------------------------
47
57
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
+
48
74
cpdef inline bint is_utc(tzinfo tz):
49
75
return (
50
76
tz is utc_pytz
51
77
or tz is utc_stdlib
52
78
or isinstance (tz, _dateutil_tzutc)
53
79
or tz is utc_dateutil_str
80
+ or is_utc_zoneinfo(tz)
54
81
)
55
82
56
83
84
+ cdef inline bint is_zoneinfo(tzinfo tz):
85
+ if ZoneInfo is None :
86
+ return False
87
+ return isinstance (tz, ZoneInfo)
88
+
89
+
57
90
cdef inline bint is_tzlocal(tzinfo tz):
58
91
return isinstance (tz, _dateutil_tzlocal)
59
92
@@ -210,6 +243,8 @@ cdef inline bint is_fixed_offset(tzinfo tz):
210
243
return 1
211
244
else :
212
245
return 0
246
+ elif is_zoneinfo(tz):
247
+ return 0
213
248
# This also implicitly accepts datetime.timezone objects which are
214
249
# considered fixed
215
250
return 1
@@ -264,6 +299,8 @@ cdef object get_dst_info(tzinfo tz):
264
299
# e.g. pytz.FixedOffset, matplotlib.dates._UTC,
265
300
# psycopg2.tz.FixedOffsetTimezone
266
301
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.
267
304
return (np.array([NPY_NAT + 1 ], dtype = np.int64),
268
305
np.array([num], dtype = np.int64),
269
306
" unknown" )
@@ -291,13 +328,13 @@ cdef object get_dst_info(tzinfo tz):
291
328
# deltas
292
329
deltas = np.array([v.offset for v in (
293
330
tz._ttinfo_before,) + tz._trans_idx], dtype = ' i8' )
294
- deltas *= 1000000000
331
+ deltas *= 1 _000_000_000
295
332
typ = ' dateutil'
296
333
297
334
elif is_fixed_offset(tz):
298
335
trans = np.array([NPY_NAT + 1 ], dtype = np.int64)
299
336
deltas = np.array([tz._ttinfo_std.offset],
300
- dtype = ' i8' ) * 1000000000
337
+ dtype = ' i8' ) * 1 _000_000_000
301
338
typ = ' fixed'
302
339
else :
303
340
# 2018-07-12 this is not reached in the tests, and this case
0 commit comments