[Python-checkins] cpython: Closes #25283: Make tm_gmtoff and tm_zone available on all platforms.

alexander.belopolsky python-checkins at python.org
Sun Sep 11 22:55:19 EDT 2016


https://hg.python.org/cpython/rev/a96101dd105c
changeset:   103680:a96101dd105c
user:        Alexander Belopolsky <alexander.belopolsky at gmail.com>
date:        Sun Sep 11 22:55:16 2016 -0400
summary:
  Closes #25283: Make tm_gmtoff and tm_zone available on all platforms.

files:
  Doc/library/time.rst |    8 +-
  Misc/NEWS            |    4 +
  Modules/timemodule.c |  114 ++++++++++++++++++++++--------
  3 files changed, 89 insertions(+), 37 deletions(-)


diff --git a/Doc/library/time.rst b/Doc/library/time.rst
--- a/Doc/library/time.rst
+++ b/Doc/library/time.rst
@@ -83,6 +83,10 @@
      and :attr:`tm_zone` attributes when platform supports corresponding
      ``struct tm`` members.
 
+  .. versionchanged:: 3.6
+     The :class:`struct_time` attributes :attr:`tm_gmtoff` and :attr:`tm_zone`
+     are now available on all platforms.
+
 * Use the following functions to convert between time representations:
 
   +-------------------------+-------------------------+-------------------------+
@@ -566,10 +570,6 @@
    :class:`struct_time`, or having elements of the wrong type, a
    :exc:`TypeError` is raised.
 
-  .. versionchanged:: 3.3
-     :attr:`tm_gmtoff` and :attr:`tm_zone` attributes are available on platforms
-     with C library supporting the corresponding fields in ``struct tm``.
-
 .. function:: time()
 
    Return the time in seconds since the epoch as a floating point number.
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -143,6 +143,10 @@
 Library
 -------
 
+- Issue #25283: Attributes tm_gmtoff and tm_zone are now available on
+  all platforms in the return values of time.localtime() and
+  time.gmtime().
+
 - Issue #24454: Regular expression match object groups are now
   accessible using __getitem__.  "mo[x]" is equivalent to
   "mo.group(x)".
diff --git a/Modules/timemodule.c b/Modules/timemodule.c
--- a/Modules/timemodule.c
+++ b/Modules/timemodule.c
@@ -250,10 +250,8 @@
     {"tm_wday", "day of week, range [0, 6], Monday is 0"},
     {"tm_yday", "day of year, range [1, 366]"},
     {"tm_isdst", "1 if summer time is in effect, 0 if not, and -1 if unknown"},
-#ifdef HAVE_STRUCT_TM_TM_ZONE
     {"tm_zone", "abbreviation of timezone name"},
     {"tm_gmtoff", "offset from UTC in seconds"},
-#endif /* HAVE_STRUCT_TM_TM_ZONE */
     {0}
 };
 
@@ -275,7 +273,11 @@
 
 
 static PyObject *
-tmtotuple(struct tm *p)
+tmtotuple(struct tm *p
+#ifndef HAVE_STRUCT_TM_TM_ZONE
+        , const char *zone, int gmtoff
+#endif
+)
 {
     PyObject *v = PyStructSequence_New(&StructTimeType);
     if (v == NULL)
@@ -296,6 +298,10 @@
     PyStructSequence_SET_ITEM(v, 9,
         PyUnicode_DecodeLocale(p->tm_zone, "surrogateescape"));
     SET(10, p->tm_gmtoff);
+#else
+    PyStructSequence_SET_ITEM(v, 9,
+        PyUnicode_DecodeLocale(zone, "surrogateescape"));
+    SET(10, gmtoff);
 #endif /* HAVE_STRUCT_TM_TM_ZONE */
 #undef SET
     if (PyErr_Occurred()) {
@@ -348,9 +354,26 @@
         return PyErr_SetFromErrno(PyExc_OSError);
     }
     buf = *local;
+#ifdef HAVE_STRUCT_TM_TM_ZONE
     return tmtotuple(&buf);
+#else
+    return tmtotuple(&buf, "UTC", 0);
+#endif
 }
 
+#ifndef HAVE_TIMEGM
+static time_t
+timegm(struct tm *p)
+{
+    /* XXX: the following implementation will not work for tm_year < 1970.
+       but it is likely that platforms that don't have timegm do not support
+       negative timestamps anyways. */
+    return p->tm_sec + p->tm_min*60 + p->tm_hour*3600 + p->tm_yday*86400 +
+        (p->tm_year-70)*31536000 + ((p->tm_year-69)/4)*86400 -
+        ((p->tm_year-1)/100)*86400 + ((p->tm_year+299)/400)*86400;
+}
+#endif
+
 PyDoc_STRVAR(gmtime_doc,
 "gmtime([seconds]) -> (tm_year, tm_mon, tm_mday, tm_hour, tm_min,\n\
                        tm_sec, tm_wday, tm_yday, tm_isdst)\n\
@@ -391,7 +414,18 @@
         return NULL;
     if (pylocaltime(&when, &buf) == -1)
         return NULL;
+#ifdef HAVE_STRUCT_TM_TM_ZONE
     return tmtotuple(&buf);
+#else
+    {
+        struct tm local = buf;
+        char zone[100];
+        int gmtoff;
+        strftime(zone, sizeof(buf), "%Z", &buf);
+        gmtoff = timegm(&buf) - when;
+        return tmtotuple(&local, zone, gmtoff);
+    }
+#endif
 }
 
 PyDoc_STRVAR(localtime_doc,
@@ -1146,6 +1180,27 @@
 Get information of the specified clock.");
 
 static void
+get_zone(char *zone, int n, struct tm *p)
+{
+#ifdef HAVE_STRUCT_TM_TM_ZONE
+    strncpy(zone, p->tm_zone ? p->tm_zone : "   ", n);
+#else
+    tzset();
+    strftime(zone, n, "%Z", p);
+#endif
+}
+
+static int
+get_gmtoff(time_t t, struct tm *p)
+{
+#ifdef HAVE_STRUCT_TM_TM_ZONE
+    return p->tm_gmtoff;
+#else
+    return timegm(p) - t;
+#endif
+}
+
+static void
 PyInit_timezone(PyObject *m) {
     /* This code moved from PyInit_time wholesale to allow calling it from
     time_tzset. In the future, some parts of it can be moved back
@@ -1177,7 +1232,6 @@
     otz1 = PyUnicode_DecodeLocale(tzname[1], "surrogateescape");
     PyModule_AddObject(m, "tzname", Py_BuildValue("(NN)", otz0, otz1));
 #else /* !HAVE_TZNAME || __GLIBC__ || __CYGWIN__*/
-#ifdef HAVE_STRUCT_TM_TM_ZONE
     {
 #define YEAR ((time_t)((365 * 24 + 6) * 3600))
         time_t t;
@@ -1186,13 +1240,13 @@
         char janname[10], julyname[10];
         t = (time((time_t *)0) / YEAR) * YEAR;
         p = localtime(&t);
-        janzone = -p->tm_gmtoff;
-        strncpy(janname, p->tm_zone ? p->tm_zone : "   ", 9);
+        get_zone(janname, 9, p);
+        janzone = -get_gmtoff(t, p);
         janname[9] = '\0';
         t += YEAR/2;
         p = localtime(&t);
-        julyzone = -p->tm_gmtoff;
-        strncpy(julyname, p->tm_zone ? p->tm_zone : "   ", 9);
+        get_zone(julyname, 9, p);
+        julyzone = -get_gmtoff(t, p);
         julyname[9] = '\0';
 
         if( janzone < julyzone ) {
@@ -1214,8 +1268,6 @@
                                              janname, julyname));
         }
     }
-#else
-#endif /* HAVE_STRUCT_TM_TM_ZONE */
 #ifdef __CYGWIN__
     tzset();
     PyModule_AddIntConstant(m, "timezone", _timezone);
@@ -1225,25 +1277,6 @@
                        Py_BuildValue("(zz)", _tzname[0], _tzname[1]));
 #endif /* __CYGWIN__ */
 #endif /* !HAVE_TZNAME || __GLIBC__ || __CYGWIN__*/
-
-#if defined(HAVE_CLOCK_GETTIME)
-    PyModule_AddIntMacro(m, CLOCK_REALTIME);
-#ifdef CLOCK_MONOTONIC
-    PyModule_AddIntMacro(m, CLOCK_MONOTONIC);
-#endif
-#ifdef CLOCK_MONOTONIC_RAW
-    PyModule_AddIntMacro(m, CLOCK_MONOTONIC_RAW);
-#endif
-#ifdef CLOCK_HIGHRES
-    PyModule_AddIntMacro(m, CLOCK_HIGHRES);
-#endif
-#ifdef CLOCK_PROCESS_CPUTIME_ID
-    PyModule_AddIntMacro(m, CLOCK_PROCESS_CPUTIME_ID);
-#endif
-#ifdef CLOCK_THREAD_CPUTIME_ID
-    PyModule_AddIntMacro(m, CLOCK_THREAD_CPUTIME_ID);
-#endif
-#endif /* HAVE_CLOCK_GETTIME */
 }
 
 
@@ -1350,17 +1383,32 @@
     /* Set, or reset, module variables like time.timezone */
     PyInit_timezone(m);
 
+#if defined(HAVE_CLOCK_GETTIME)
+    PyModule_AddIntMacro(m, CLOCK_REALTIME);
+#ifdef CLOCK_MONOTONIC
+    PyModule_AddIntMacro(m, CLOCK_MONOTONIC);
+#endif
+#ifdef CLOCK_MONOTONIC_RAW
+    PyModule_AddIntMacro(m, CLOCK_MONOTONIC_RAW);
+#endif
+#ifdef CLOCK_HIGHRES
+    PyModule_AddIntMacro(m, CLOCK_HIGHRES);
+#endif
+#ifdef CLOCK_PROCESS_CPUTIME_ID
+    PyModule_AddIntMacro(m, CLOCK_PROCESS_CPUTIME_ID);
+#endif
+#ifdef CLOCK_THREAD_CPUTIME_ID
+    PyModule_AddIntMacro(m, CLOCK_THREAD_CPUTIME_ID);
+#endif
+#endif /* HAVE_CLOCK_GETTIME */
+
     if (!initialized) {
         if (PyStructSequence_InitType2(&StructTimeType,
                                        &struct_time_type_desc) < 0)
             return NULL;
     }
     Py_INCREF(&StructTimeType);
-#ifdef HAVE_STRUCT_TM_TM_ZONE
     PyModule_AddIntConstant(m, "_STRUCT_TM_ITEMS", 11);
-#else
-    PyModule_AddIntConstant(m, "_STRUCT_TM_ITEMS", 9);
-#endif
     PyModule_AddObject(m, "struct_time", (PyObject*) &StructTimeType);
     initialized = 1;
     return m;

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list