]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-30155: Add macros to get tzinfo from datetime instances (GH-21633)
authorZackery Spytz <zspytz@gmail.com>
Wed, 23 Sep 2020 18:43:45 +0000 (12:43 -0600)
committerGitHub <noreply@github.com>
Wed, 23 Sep 2020 18:43:45 +0000 (14:43 -0400)
Add PyDateTime_DATE_GET_TZINFO() and PyDateTime_TIME_GET_TZINFO()
macros.

Doc/c-api/datetime.rst
Doc/whatsnew/3.10.rst
Include/datetime.h
Lib/test/datetimetester.py
Misc/NEWS.d/next/C API/2020-07-26-19-39-45.bpo-30155.rHZRJ_.rst [new file with mode: 0644]
Modules/_datetimemodule.c
Modules/_testcapimodule.c
Modules/_zoneinfo.c

index bd4f1ff446bcf4c44195b09f78de30dd999d69a0..415ce4cac67f154c226c01ecd7aad889c993fbf2 100644 (file)
@@ -185,6 +185,11 @@ must not be ``NULL``, and the type is not checked:
 
    Return the microsecond, as an int from 0 through 999999.
 
+.. c:function:: PyObject* PyDateTime_DATE_GET_TZINFO(PyDateTime_DateTime *o)
+
+   Return the tzinfo (which may be ``None``).
+
+   .. versionadded:: 3.10
 
 Macros to extract fields from time objects.  The argument must be an instance of
 :c:data:`PyDateTime_Time`, including subclasses. The argument must not be ``NULL``,
@@ -209,6 +214,12 @@ and the type is not checked:
 
    Return the microsecond, as an int from 0 through 999999.
 
+.. c:function:: PyObject* PyDateTime_TIME_GET_TZINFO(PyDateTime_Time *o)
+
+   Return the tzinfo (which may be ``None``).
+
+   .. versionadded:: 3.10
+
 
 Macros to extract fields from time delta objects.  The argument must be an
 instance of :c:data:`PyDateTime_Delta`, including subclasses. The argument must
index 606fad2fdcf059249d7a2f4c70bf1865f05c71d3..1228f2695496c5870601ed416d17ed4b5d660b05 100644 (file)
@@ -231,6 +231,12 @@ New Features
   Python executable.
   (Contributed by Victor Stinner in :issue:`23427`.)
 
+* The :c:func:`PyDateTime_DATE_GET_TZINFO` and
+  :c:func:`PyDateTime_TIME_GET_TZINFO` macros have been added for accessing
+  the ``tzinfo`` attributes of :class:`datetime.datetime` and
+  :class:`datetime.time` objects.
+  (Contributed by Zackery Spytz in :issue:`30155`.)
+
 Porting to Python 3.10
 ----------------------
 
index 5d9f2558f924d0b66403348195bd7fdfbe8d30e7..bb565201a164d7ed66c66697ae3ac5d6951b54b2 100644 (file)
@@ -115,6 +115,10 @@ typedef struct
 
 
 /* Apply for date and datetime instances. */
+
+// o is a pointer to a time or a datetime object.
+#define _PyDateTime_HAS_TZINFO(o)  (((_PyDateTime_BaseTZInfo *)(o))->hastzinfo)
+
 #define PyDateTime_GET_YEAR(o)     ((((PyDateTime_Date*)o)->data[0] << 8) | \
                      ((PyDateTime_Date*)o)->data[1])
 #define PyDateTime_GET_MONTH(o)    (((PyDateTime_Date*)o)->data[2])
@@ -128,6 +132,8 @@ typedef struct
      (((PyDateTime_DateTime*)o)->data[8] << 8)  |       \
       ((PyDateTime_DateTime*)o)->data[9])
 #define PyDateTime_DATE_GET_FOLD(o)        (((PyDateTime_DateTime*)o)->fold)
+#define PyDateTime_DATE_GET_TZINFO(o)      (_PyDateTime_HAS_TZINFO(o) ? \
+    ((PyDateTime_DateTime *)(o))->tzinfo : Py_None)
 
 /* Apply for time instances. */
 #define PyDateTime_TIME_GET_HOUR(o)        (((PyDateTime_Time*)o)->data[0])
@@ -138,6 +144,8 @@ typedef struct
      (((PyDateTime_Time*)o)->data[4] << 8)  |           \
       ((PyDateTime_Time*)o)->data[5])
 #define PyDateTime_TIME_GET_FOLD(o)        (((PyDateTime_Time*)o)->fold)
+#define PyDateTime_TIME_GET_TZINFO(o)      (_PyDateTime_HAS_TZINFO(o) ? \
+    ((PyDateTime_Time *)(o))->tzinfo : Py_None)
 
 /* Apply for time delta instances */
 #define PyDateTime_DELTA_GET_DAYS(o)         (((PyDateTime_Delta*)o)->days)
index 520a51df87999764d9be631c48ff13a376fc3480..8b61c26f9e5c24cfbe5c02ad84a9a96f7ae82334 100644 (file)
@@ -5991,30 +5991,36 @@ class CapiTest(unittest.TestCase):
 
         for klass in [datetime, DateTimeSubclass]:
             for args in [(1993, 8, 26, 22, 12, 55, 99999),
-                         (1993, 8, 26, 22, 12, 55, 99999)]:
+                         (1993, 8, 26, 22, 12, 55, 99999,
+                          timezone.utc)]:
                 d = klass(*args)
                 with self.subTest(cls=klass, date=args):
-                    hour, minute, second, microsecond = _testcapi.PyDateTime_DATE_GET(d)
+                    hour, minute, second, microsecond, tzinfo = \
+                                            _testcapi.PyDateTime_DATE_GET(d)
 
                     self.assertEqual(hour, d.hour)
                     self.assertEqual(minute, d.minute)
                     self.assertEqual(second, d.second)
                     self.assertEqual(microsecond, d.microsecond)
+                    self.assertIs(tzinfo, d.tzinfo)
 
     def test_PyDateTime_TIME_GET(self):
         class TimeSubclass(time):
             pass
 
         for klass in [time, TimeSubclass]:
-            for args in [(12, 30, 20, 10), (12, 30, 20, 10)]:
+            for args in [(12, 30, 20, 10),
+                         (12, 30, 20, 10, timezone.utc)]:
                 d = klass(*args)
                 with self.subTest(cls=klass, date=args):
-                    hour, minute, second, microsecond = _testcapi.PyDateTime_TIME_GET(d)
+                    hour, minute, second, microsecond, tzinfo = \
+                                              _testcapi.PyDateTime_TIME_GET(d)
 
                     self.assertEqual(hour, d.hour)
                     self.assertEqual(minute, d.minute)
                     self.assertEqual(second, d.second)
                     self.assertEqual(microsecond, d.microsecond)
+                    self.assertIs(tzinfo, d.tzinfo)
 
     def test_timezones_offset_zero(self):
         utc0, utc1, non_utc = _testcapi.get_timezones_offset_zero()
diff --git a/Misc/NEWS.d/next/C API/2020-07-26-19-39-45.bpo-30155.rHZRJ_.rst b/Misc/NEWS.d/next/C API/2020-07-26-19-39-45.bpo-30155.rHZRJ_.rst
new file mode 100644 (file)
index 0000000..a276759
--- /dev/null
@@ -0,0 +1,3 @@
+Add :c:func:`PyDateTime_DATE_GET_TZINFO` and
+:c:func:`PyDateTime_TIME_GET_TZINFO` macros for accessing the ``tzinfo``
+attributes of :class:`datetime.datetime` and :class:`datetime.time` objects.
index 74a54e74ae0fec93fe10bcb488f333c74fc3933a..0631272429f4f14689f16bf0737b958eca8add1b 100644 (file)
@@ -115,14 +115,9 @@ class datetime.IsoCalendarDate "PyDateTime_IsoCalendarDate *" "&PyDateTime_IsoCa
 #define SET_TD_SECONDS(o, v)    ((o)->seconds = (v))
 #define SET_TD_MICROSECONDS(o, v) ((o)->microseconds = (v))
 
-/* p is a pointer to a time or a datetime object; HASTZINFO(p) returns
- * p->hastzinfo.
- */
-#define HASTZINFO(p) (((_PyDateTime_BaseTZInfo *)(p))->hastzinfo)
-#define GET_TIME_TZINFO(p) (HASTZINFO(p) ? \
-                            ((PyDateTime_Time *)(p))->tzinfo : Py_None)
-#define GET_DT_TZINFO(p) (HASTZINFO(p) ? \
-                          ((PyDateTime_DateTime *)(p))->tzinfo : Py_None)
+#define HASTZINFO               _PyDateTime_HAS_TZINFO
+#define GET_TIME_TZINFO         PyDateTime_TIME_GET_TZINFO
+#define GET_DT_TZINFO           PyDateTime_DATE_GET_TZINFO
 /* M is a char or int claiming to be a valid month.  The macro is equivalent
  * to the two-sided Python test
  *      1 <= M <= 12
index 7536d29535038c7ca7a1785918e87f36cfbe8552..0e098779696b737dacc27615f23c6a0020347978 100644 (file)
@@ -2677,8 +2677,9 @@ test_PyDateTime_DATE_GET(PyObject *self, PyObject *obj)
     minute = PyDateTime_DATE_GET_MINUTE(obj);
     second = PyDateTime_DATE_GET_SECOND(obj);
     microsecond = PyDateTime_DATE_GET_MICROSECOND(obj);
+    PyObject *tzinfo = PyDateTime_DATE_GET_TZINFO(obj);
 
-    return Py_BuildValue("(llll)", hour, minute, second, microsecond);
+    return Py_BuildValue("(llllO)", hour, minute, second, microsecond, tzinfo);
 }
 
 static PyObject *
@@ -2690,8 +2691,9 @@ test_PyDateTime_TIME_GET(PyObject *self, PyObject *obj)
     minute = PyDateTime_TIME_GET_MINUTE(obj);
     second = PyDateTime_TIME_GET_SECOND(obj);
     microsecond = PyDateTime_TIME_GET_MICROSECOND(obj);
+    PyObject *tzinfo = PyDateTime_TIME_GET_TZINFO(obj);
 
-    return Py_BuildValue("(llll)", hour, minute, second, microsecond);
+    return Py_BuildValue("(llllO)", hour, minute, second, microsecond, tzinfo);
 }
 
 static PyObject *
index 2cee65fac6dd042aefccde501251b3801f6cc371..bee59b8d2ae0cc63503dd56b6a2b952c7db85d13 100644 (file)
@@ -484,9 +484,7 @@ zoneinfo_tzname(PyObject *self, PyObject *dt)
     return tti->tzname;
 }
 
-#define HASTZINFO(p) (((_PyDateTime_BaseTZInfo *)(p))->hastzinfo)
-#define GET_DT_TZINFO(p) \
-    (HASTZINFO(p) ? ((PyDateTime_DateTime *)(p))->tzinfo : Py_None)
+#define GET_DT_TZINFO PyDateTime_DATE_GET_TZINFO
 
 static PyObject *
 zoneinfo_fromutc(PyObject *obj_self, PyObject *dt)