Closes #25283: Make tm_gmtoff and tm_zone available on all platforms.
This commit is contained in:
parent
a3222b8424
commit
18f3a9b93c
|
@ -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.
|
||||
|
|
|
@ -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)".
|
||||
|
|
|
@ -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,
|
||||
|
@ -1145,6 +1179,27 @@ PyDoc_STRVAR(get_clock_info_doc,
|
|||
\n\
|
||||
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
|
||||
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue