Skip to content

Commit 2e4dd33

Browse files
authored
bpo-30155: Add macros to get tzinfo from datetime instances (GH-21633)
Add PyDateTime_DATE_GET_TZINFO() and PyDateTime_TIME_GET_TZINFO() macros.
1 parent 9c4eac7 commit 2e4dd33

File tree

8 files changed

+46
-17
lines changed

8 files changed

+46
-17
lines changed

Doc/c-api/datetime.rst

+11
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,11 @@ must not be ``NULL``, and the type is not checked:
185185
186186
Return the microsecond, as an int from 0 through 999999.
187187
188+
.. c:function:: PyObject* PyDateTime_DATE_GET_TZINFO(PyDateTime_DateTime *o)
189+
190+
Return the tzinfo (which may be ``None``).
191+
192+
.. versionadded:: 3.10
188193
189194
Macros to extract fields from time objects. The argument must be an instance of
190195
:c:data:`PyDateTime_Time`, including subclasses. The argument must not be ``NULL``,
@@ -209,6 +214,12 @@ and the type is not checked:
209214
210215
Return the microsecond, as an int from 0 through 999999.
211216
217+
.. c:function:: PyObject* PyDateTime_TIME_GET_TZINFO(PyDateTime_Time *o)
218+
219+
Return the tzinfo (which may be ``None``).
220+
221+
.. versionadded:: 3.10
222+
212223
213224
Macros to extract fields from time delta objects. The argument must be an
214225
instance of :c:data:`PyDateTime_Delta`, including subclasses. The argument must

Doc/whatsnew/3.10.rst

+6
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,12 @@ New Features
231231
Python executable.
232232
(Contributed by Victor Stinner in :issue:`23427`.)
233233

234+
* The :c:func:`PyDateTime_DATE_GET_TZINFO` and
235+
:c:func:`PyDateTime_TIME_GET_TZINFO` macros have been added for accessing
236+
the ``tzinfo`` attributes of :class:`datetime.datetime` and
237+
:class:`datetime.time` objects.
238+
(Contributed by Zackery Spytz in :issue:`30155`.)
239+
234240
Porting to Python 3.10
235241
----------------------
236242

Include/datetime.h

+8
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ typedef struct
115115

116116

117117
/* Apply for date and datetime instances. */
118+
119+
// o is a pointer to a time or a datetime object.
120+
#define _PyDateTime_HAS_TZINFO(o) (((_PyDateTime_BaseTZInfo *)(o))->hastzinfo)
121+
118122
#define PyDateTime_GET_YEAR(o) ((((PyDateTime_Date*)o)->data[0] << 8) | \
119123
((PyDateTime_Date*)o)->data[1])
120124
#define PyDateTime_GET_MONTH(o) (((PyDateTime_Date*)o)->data[2])
@@ -128,6 +132,8 @@ typedef struct
128132
(((PyDateTime_DateTime*)o)->data[8] << 8) | \
129133
((PyDateTime_DateTime*)o)->data[9])
130134
#define PyDateTime_DATE_GET_FOLD(o) (((PyDateTime_DateTime*)o)->fold)
135+
#define PyDateTime_DATE_GET_TZINFO(o) (_PyDateTime_HAS_TZINFO(o) ? \
136+
((PyDateTime_DateTime *)(o))->tzinfo : Py_None)
131137

132138
/* Apply for time instances. */
133139
#define PyDateTime_TIME_GET_HOUR(o) (((PyDateTime_Time*)o)->data[0])
@@ -138,6 +144,8 @@ typedef struct
138144
(((PyDateTime_Time*)o)->data[4] << 8) | \
139145
((PyDateTime_Time*)o)->data[5])
140146
#define PyDateTime_TIME_GET_FOLD(o) (((PyDateTime_Time*)o)->fold)
147+
#define PyDateTime_TIME_GET_TZINFO(o) (_PyDateTime_HAS_TZINFO(o) ? \
148+
((PyDateTime_Time *)(o))->tzinfo : Py_None)
141149

142150
/* Apply for time delta instances */
143151
#define PyDateTime_DELTA_GET_DAYS(o) (((PyDateTime_Delta*)o)->days)

Lib/test/datetimetester.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -5991,30 +5991,36 @@ class DateTimeSubclass(datetime):
59915991

59925992
for klass in [datetime, DateTimeSubclass]:
59935993
for args in [(1993, 8, 26, 22, 12, 55, 99999),
5994-
(1993, 8, 26, 22, 12, 55, 99999)]:
5994+
(1993, 8, 26, 22, 12, 55, 99999,
5995+
timezone.utc)]:
59955996
d = klass(*args)
59965997
with self.subTest(cls=klass, date=args):
5997-
hour, minute, second, microsecond = _testcapi.PyDateTime_DATE_GET(d)
5998+
hour, minute, second, microsecond, tzinfo = \
5999+
_testcapi.PyDateTime_DATE_GET(d)
59986000

59996001
self.assertEqual(hour, d.hour)
60006002
self.assertEqual(minute, d.minute)
60016003
self.assertEqual(second, d.second)
60026004
self.assertEqual(microsecond, d.microsecond)
6005+
self.assertIs(tzinfo, d.tzinfo)
60036006

60046007
def test_PyDateTime_TIME_GET(self):
60056008
class TimeSubclass(time):
60066009
pass
60076010

60086011
for klass in [time, TimeSubclass]:
6009-
for args in [(12, 30, 20, 10), (12, 30, 20, 10)]:
6012+
for args in [(12, 30, 20, 10),
6013+
(12, 30, 20, 10, timezone.utc)]:
60106014
d = klass(*args)
60116015
with self.subTest(cls=klass, date=args):
6012-
hour, minute, second, microsecond = _testcapi.PyDateTime_TIME_GET(d)
6016+
hour, minute, second, microsecond, tzinfo = \
6017+
_testcapi.PyDateTime_TIME_GET(d)
60136018

60146019
self.assertEqual(hour, d.hour)
60156020
self.assertEqual(minute, d.minute)
60166021
self.assertEqual(second, d.second)
60176022
self.assertEqual(microsecond, d.microsecond)
6023+
self.assertIs(tzinfo, d.tzinfo)
60186024

60196025
def test_timezones_offset_zero(self):
60206026
utc0, utc1, non_utc = _testcapi.get_timezones_offset_zero()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Add :c:func:`PyDateTime_DATE_GET_TZINFO` and
2+
:c:func:`PyDateTime_TIME_GET_TZINFO` macros for accessing the ``tzinfo``
3+
attributes of :class:`datetime.datetime` and :class:`datetime.time` objects.

Modules/_datetimemodule.c

+3-8
Original file line numberDiff line numberDiff line change
@@ -115,14 +115,9 @@ class datetime.IsoCalendarDate "PyDateTime_IsoCalendarDate *" "&PyDateTime_IsoCa
115115
#define SET_TD_SECONDS(o, v) ((o)->seconds = (v))
116116
#define SET_TD_MICROSECONDS(o, v) ((o)->microseconds = (v))
117117

118-
/* p is a pointer to a time or a datetime object; HASTZINFO(p) returns
119-
* p->hastzinfo.
120-
*/
121-
#define HASTZINFO(p) (((_PyDateTime_BaseTZInfo *)(p))->hastzinfo)
122-
#define GET_TIME_TZINFO(p) (HASTZINFO(p) ? \
123-
((PyDateTime_Time *)(p))->tzinfo : Py_None)
124-
#define GET_DT_TZINFO(p) (HASTZINFO(p) ? \
125-
((PyDateTime_DateTime *)(p))->tzinfo : Py_None)
118+
#define HASTZINFO _PyDateTime_HAS_TZINFO
119+
#define GET_TIME_TZINFO PyDateTime_TIME_GET_TZINFO
120+
#define GET_DT_TZINFO PyDateTime_DATE_GET_TZINFO
126121
/* M is a char or int claiming to be a valid month. The macro is equivalent
127122
* to the two-sided Python test
128123
* 1 <= M <= 12

Modules/_testcapimodule.c

+4-2
Original file line numberDiff line numberDiff line change
@@ -2677,8 +2677,9 @@ test_PyDateTime_DATE_GET(PyObject *self, PyObject *obj)
26772677
minute = PyDateTime_DATE_GET_MINUTE(obj);
26782678
second = PyDateTime_DATE_GET_SECOND(obj);
26792679
microsecond = PyDateTime_DATE_GET_MICROSECOND(obj);
2680+
PyObject *tzinfo = PyDateTime_DATE_GET_TZINFO(obj);
26802681

2681-
return Py_BuildValue("(llll)", hour, minute, second, microsecond);
2682+
return Py_BuildValue("(llllO)", hour, minute, second, microsecond, tzinfo);
26822683
}
26832684

26842685
static PyObject *
@@ -2690,8 +2691,9 @@ test_PyDateTime_TIME_GET(PyObject *self, PyObject *obj)
26902691
minute = PyDateTime_TIME_GET_MINUTE(obj);
26912692
second = PyDateTime_TIME_GET_SECOND(obj);
26922693
microsecond = PyDateTime_TIME_GET_MICROSECOND(obj);
2694+
PyObject *tzinfo = PyDateTime_TIME_GET_TZINFO(obj);
26932695

2694-
return Py_BuildValue("(llll)", hour, minute, second, microsecond);
2696+
return Py_BuildValue("(llllO)", hour, minute, second, microsecond, tzinfo);
26952697
}
26962698

26972699
static PyObject *

Modules/_zoneinfo.c

+1-3
Original file line numberDiff line numberDiff line change
@@ -484,9 +484,7 @@ zoneinfo_tzname(PyObject *self, PyObject *dt)
484484
return tti->tzname;
485485
}
486486

487-
#define HASTZINFO(p) (((_PyDateTime_BaseTZInfo *)(p))->hastzinfo)
488-
#define GET_DT_TZINFO(p) \
489-
(HASTZINFO(p) ? ((PyDateTime_DateTime *)(p))->tzinfo : Py_None)
487+
#define GET_DT_TZINFO PyDateTime_DATE_GET_TZINFO
490488

491489
static PyObject *
492490
zoneinfo_fromutc(PyObject *obj_self, PyObject *dt)

0 commit comments

Comments
 (0)