summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/time.rst8
-rw-r--r--Misc/NEWS4
-rw-r--r--Modules/timemodule.c114
3 files changed, 89 insertions, 37 deletions
diff --git a/Doc/library/time.rst b/Doc/library/time.rst
index 7c81ce7..ae17f6f 100644
--- a/Doc/library/time.rst
+++ b/Doc/library/time.rst
@@ -83,6 +83,10 @@ An explanation of some terminology and conventions is in order.
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 @@ The module defines the following functions and data items:
: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
index 1eb37ea..35f1d65 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -143,6 +143,10 @@ Core and Builtins
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
index 9474644..ea7d906 100644
--- a/Modules/timemodule.c
+++ b/Modules/timemodule.c
@@ -250,10 +250,8 @@ static PyStructSequence_Field struct_time_type_fields[] = {
{"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 PyTypeObject StructTimeType;
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 @@ tmtotuple(struct tm *p)
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 @@ time_gmtime(PyObject *self, PyObject *args)
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 @@ time_localtime(PyObject *self, PyObject *args)
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 @@ PyDoc_STRVAR(get_clock_info_doc,
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 @@ PyInit_timezone(PyObject *m) {
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 @@ PyInit_timezone(PyObject *m) {
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 @@ PyInit_timezone(PyObject *m) {
janname, julyname));
}
}
-#else
-#endif /* HAVE_STRUCT_TM_TM_ZONE */
#ifdef __CYGWIN__
tzset();
PyModule_AddIntConstant(m, "timezone", _timezone);
@@ -1225,25 +1277,6 @@ PyInit_timezone(PyObject *m) {
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 @@ PyInit_time(void)
/* 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;