[Python-checkins] cpython (3.6): Issue #28148: Stop using localtime() and gmtime() in the time module.

alexander.belopolsky python-checkins at python.org
Wed Sep 28 17:32:40 EDT 2016


https://hg.python.org/cpython/rev/c81b9107ec42
changeset:   104141:c81b9107ec42
branch:      3.6
parent:      104139:e6dcb14829cf
user:        Alexander Belopolsky <alexander.belopolsky at gmail.com>
date:        Wed Sep 28 17:31:35 2016 -0400
summary:
  Issue #28148: Stop using localtime() and gmtime() in the time module.

Introduced platform independent _PyTime_localtime API that is similar
to POSIX localtime_r, but available on all platforms.  Patch by Ed
Schouten.

files:
  Include/pytime.h          |   8 +++
  Misc/ACKS                 |   1 +
  Modules/_datetimemodule.c |  67 ++++++--------------------
  Modules/timemodule.c      |  55 +++++----------------
  Python/pytime.c           |  52 ++++++++++++++++++++
  5 files changed, 91 insertions(+), 92 deletions(-)


diff --git a/Include/pytime.h b/Include/pytime.h
--- a/Include/pytime.h
+++ b/Include/pytime.h
@@ -184,6 +184,14 @@
    Return 0 on success, raise an exception and return -1 on error. */
 PyAPI_FUNC(int) _PyTime_Init(void);
 
+/* Converts a timestamp to the Gregorian time, using the local time zone.
+   Return 0 on success, raise an exception and return -1 on error. */
+PyAPI_FUNC(int) _PyTime_localtime(time_t t, struct tm *tm);
+
+/* Converts a timestamp to the Gregorian time, assuming UTC.
+   Return 0 on success, raise an exception and return -1 on error. */
+PyAPI_FUNC(int) _PyTime_gmtime(time_t t, struct tm *tm);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1340,6 +1340,7 @@
 Peter Schneider-Kamp
 Arvin Schnell
 Nofar Schnider
+Ed Schouten
 Scott Schram
 Robin Schreiber
 Chad J. Schroeder
diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c
--- a/Modules/_datetimemodule.c
+++ b/Modules/_datetimemodule.c
@@ -9,18 +9,6 @@
 
 #ifdef MS_WINDOWS
 #  include <winsock2.h>         /* struct timeval */
-static struct tm *localtime_r(const time_t *timep, struct tm *result)
-{
-    if (localtime_s(result, timep) == 0)
-        return result;
-    return NULL;
-}
-static struct tm *gmtime_r(const time_t *timep, struct tm *result)
-{
-    if (gmtime_s(result, timep) == 0)
-        return result;
-    return NULL;
-}
 #endif
 
 /* Differentiate between building the core module and building extension
@@ -2529,15 +2517,8 @@
     if (_PyTime_ObjectToTime_t(obj, &t, _PyTime_ROUND_FLOOR) == -1)
         return NULL;
 
-    if (localtime_r(&t, &tm) == NULL) {
-        /* unconvertible time */
-#ifdef EINVAL
-        if (errno == 0)
-            errno = EINVAL;
-#endif
-        PyErr_SetFromErrno(PyExc_OSError);
+    if (_PyTime_localtime(t, &tm) != 0)
         return NULL;
-    }
 
     return PyObject_CallFunction(cls, "iii",
                                  tm.tm_year + 1900,
@@ -4199,8 +4180,9 @@
     return self;
 }
 
-/* TM_FUNC is the shared type of localtime_r() and gmtime_r(). */
-typedef struct tm *(*TM_FUNC)(const time_t *timer, struct tm*);
+/* TM_FUNC is the shared type of _PyTime_localtime() and
+ * _PyTime_gmtime(). */
+typedef int (*TM_FUNC)(time_t timer, struct tm*);
 
 /* As of version 2015f max fold in IANA database is
  * 23 hours at 1969-09-30 13:00:00 in Kwajalein. */
@@ -4229,10 +4211,8 @@
         return -1;
     }
     /* XXX: add bounds checking */
-    if (localtime_r(&t, &local_time) == NULL) {
-        PyErr_SetFromErrno(PyExc_OSError);
+    if (_PyTime_localtime(t, &local_time) != 0)
         return -1;
-    }
     return utc_to_seconds(local_time.tm_year + 1900,
                           local_time.tm_mon + 1,
                           local_time.tm_mday,
@@ -4252,13 +4232,8 @@
     struct tm tm;
     int year, month, day, hour, minute, second, fold = 0;
 
-    if (f(&timet, &tm) == NULL) {
-#ifdef EINVAL
-        if (errno == 0)
-            errno = EINVAL;
-#endif
-        return PyErr_SetFromErrno(PyExc_OSError);
-    }
+    if (f(timet, &tm) != 0)
+        return NULL;
 
     year = tm.tm_year + 1900;
     month = tm.tm_mon + 1;
@@ -4273,7 +4248,7 @@
      */
     second = Py_MIN(59, tm.tm_sec);
 
-    if (tzinfo == Py_None && f == localtime_r) {
+    if (tzinfo == Py_None && f == _PyTime_localtime) {
         long long probe_seconds, result_seconds, transition;
 
         result_seconds = utc_to_seconds(year, month, day,
@@ -4361,7 +4336,8 @@
         return NULL;
 
     self = datetime_best_possible((PyObject *)type,
-                                  tz == Py_None ? localtime_r : gmtime_r,
+                                  tz == Py_None ? _PyTime_localtime :
+                                  _PyTime_gmtime,
                                   tz);
     if (self != NULL && tz != Py_None) {
         /* Convert UTC to tzinfo's zone. */
@@ -4376,7 +4352,7 @@
 static PyObject *
 datetime_utcnow(PyObject *cls, PyObject *dummy)
 {
-    return datetime_best_possible(cls, gmtime_r, Py_None);
+    return datetime_best_possible(cls, _PyTime_gmtime, Py_None);
 }
 
 /* Return new local datetime from timestamp (Python timestamp -- a double). */
@@ -4395,7 +4371,8 @@
         return NULL;
 
     self = datetime_from_timestamp(cls,
-                                   tzinfo == Py_None ? localtime_r : gmtime_r,
+                                   tzinfo == Py_None ? _PyTime_localtime :
+                                   _PyTime_gmtime,
                                    timestamp,
                                    tzinfo);
     if (self != NULL && tzinfo != Py_None) {
@@ -4413,7 +4390,7 @@
     PyObject *result = NULL;
 
     if (PyArg_ParseTuple(args, "O:utcfromtimestamp", &timestamp))
-        result = datetime_from_timestamp(cls, gmtime_r, timestamp,
+        result = datetime_from_timestamp(cls, _PyTime_gmtime, timestamp,
                                          Py_None);
     return result;
 }
@@ -5040,14 +5017,8 @@
     PyObject *nameo = NULL;
     const char *zone = NULL;
 
-    if (localtime_r(&timestamp, &local_time_tm) == NULL) {
-#ifdef EINVAL
-        if (errno == 0)
-            errno = EINVAL;
-#endif
-        PyErr_SetFromErrno(PyExc_OSError);
+    if (_PyTime_localtime(timestamp, &local_time_tm) != 0)
         return NULL;
-    }
 #ifdef HAVE_STRUCT_TM_TM_ZONE
     zone = local_time_tm.tm_zone;
     delta = new_delta(0, local_time_tm.tm_gmtoff, 0, 1);
@@ -5067,14 +5038,8 @@
         if (local_time == NULL) {
             return NULL;
         }
-        if (gmtime_r(&timestamp, &utc_time_tm) == NULL) {
-#ifdef EINVAL
-            if (errno == 0)
-                errno = EINVAL;
-#endif
-            PyErr_SetFromErrno(PyExc_OSError);
+        if (_PyTime_gmtime(timestamp, &utc_time_tm) != 0)
             return NULL;
-        }
         utc_time = new_datetime(utc_time_tm.tm_year + 1900,
                                 utc_time_tm.tm_mon + 1,
                                 utc_time_tm.tm_mday,
diff --git a/Modules/timemodule.c b/Modules/timemodule.c
--- a/Modules/timemodule.c
+++ b/Modules/timemodule.c
@@ -343,21 +343,14 @@
 time_gmtime(PyObject *self, PyObject *args)
 {
     time_t when;
-    struct tm buf, *local;
+    struct tm buf;
 
     if (!parse_time_t_args(args, "|O:gmtime", &when))
         return NULL;
 
     errno = 0;
-    local = gmtime(&when);
-    if (local == NULL) {
-#ifdef EINVAL
-        if (errno == 0)
-            errno = EINVAL;
-#endif
-        return PyErr_SetFromErrno(PyExc_OSError);
-    }
-    buf = *local;
+    if (_PyTime_gmtime(when, &buf) != 0)
+        return NULL;
 #ifdef HAVE_STRUCT_TM_TM_ZONE
     return tmtotuple(&buf);
 #else
@@ -388,26 +381,6 @@
 If the platform supports the tm_gmtoff and tm_zone, they are available as\n\
 attributes only.");
 
-static int
-pylocaltime(time_t *timep, struct tm *result)
-{
-    struct tm *local;
-
-    assert (timep != NULL);
-    local = localtime(timep);
-    if (local == NULL) {
-        /* unconvertible time */
-#ifdef EINVAL
-        if (errno == 0)
-            errno = EINVAL;
-#endif
-        PyErr_SetFromErrno(PyExc_OSError);
-        return -1;
-    }
-    *result = *local;
-    return 0;
-}
-
 static PyObject *
 time_localtime(PyObject *self, PyObject *args)
 {
@@ -416,7 +389,7 @@
 
     if (!parse_time_t_args(args, "|O:localtime", &when))
         return NULL;
-    if (pylocaltime(&when, &buf) == -1)
+    if (_PyTime_localtime(when, &buf) != 0)
         return NULL;
 #ifdef HAVE_STRUCT_TM_TM_ZONE
     return tmtotuple(&buf);
@@ -611,7 +584,7 @@
 
     if (tup == NULL) {
         time_t tt = time(NULL);
-        if (pylocaltime(&tt, &buf) == -1)
+        if (_PyTime_localtime(tt, &buf) != 0)
             return NULL;
     }
     else if (!gettmarg(tup, &buf) || !checktm(&buf))
@@ -796,7 +769,7 @@
         return NULL;
     if (tup == NULL) {
         time_t tt = time(NULL);
-        if (pylocaltime(&tt, &buf) == -1)
+        if (_PyTime_localtime(tt, &buf) != 0)
             return NULL;
 
     } else if (!gettmarg(tup, &buf) || !checktm(&buf))
@@ -818,7 +791,7 @@
     struct tm buf;
     if (!parse_time_t_args(args, "|O:ctime", &tt))
         return NULL;
-    if (pylocaltime(&tt, &buf) == -1)
+    if (_PyTime_localtime(tt, &buf) != 0)
         return NULL;
     return _asctime(&buf);
 }
@@ -1239,18 +1212,18 @@
     {
 #define YEAR ((time_t)((365 * 24 + 6) * 3600))
         time_t t;
-        struct tm *p;
+        struct tm p;
         long janzone, julyzone;
         char janname[10], julyname[10];
         t = (time((time_t *)0) / YEAR) * YEAR;
-        p = localtime(&t);
-        get_zone(janname, 9, p);
-        janzone = -get_gmtoff(t, p);
+        _PyTime_localtime(t, &p);
+        get_zone(janname, 9, &p);
+        janzone = -get_gmtoff(t, &p);
         janname[9] = '\0';
         t += YEAR/2;
-        p = localtime(&t);
-        get_zone(julyname, 9, p);
-        julyzone = -get_gmtoff(t, p);
+        _PyTime_localtime(t, &p);
+        get_zone(julyname, 9, &p);
+        julyzone = -get_gmtoff(t, &p);
         julyname[9] = '\0';
 
         if( janzone < julyzone ) {
diff --git a/Python/pytime.c b/Python/pytime.c
--- a/Python/pytime.c
+++ b/Python/pytime.c
@@ -766,3 +766,55 @@
 
     return 0;
 }
+
+int
+_PyTime_localtime(time_t t, struct tm *tm)
+{
+#ifdef MS_WINDOWS
+    int error;
+
+    error = localtime_s(tm, &t);
+    if (error != 0) {
+        errno = error;
+        PyErr_SetFromErrno(PyExc_OSError);
+        return -1;
+    }
+    return 0;
+#else /* !MS_WINDOWS */
+    if (localtime_r(&t, tm) == NULL) {
+#ifdef EINVAL
+        if (errno == 0)
+            errno = EINVAL;
+#endif
+        PyErr_SetFromErrno(PyExc_OSError);
+        return -1;
+    }
+    return 0;
+#endif /* MS_WINDOWS */
+}
+
+int
+_PyTime_gmtime(time_t t, struct tm *tm)
+{
+#ifdef MS_WINDOWS
+    int error;
+
+    error = gmtime_s(tm, &t);
+    if (error != 0) {
+        errno = error;
+        PyErr_SetFromErrno(PyExc_OSError);
+        return -1;
+    }
+    return 0;
+#else /* !MS_WINDOWS */
+    if (gmtime_r(&t, tm) == NULL) {
+#ifdef EINVAL
+        if (errno == 0)
+            errno = EINVAL;
+#endif
+        PyErr_SetFromErrno(PyExc_OSError);
+        return -1;
+    }
+    return 0;
+#endif /* MS_WINDOWS */
+}

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


More information about the Python-checkins mailing list