mirror of https://github.com/python/cpython
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.
This commit is contained in:
parent
e5ccf3d699
commit
3e7a3cb903
|
@ -184,6 +184,14 @@ PyAPI_FUNC(int) _PyTime_GetMonotonicClockWithInfo(
|
|||
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
|
||||
|
|
|
@ -1340,6 +1340,7 @@ Michael Schneider
|
|||
Peter Schneider-Kamp
|
||||
Arvin Schnell
|
||||
Nofar Schnider
|
||||
Ed Schouten
|
||||
Scott Schram
|
||||
Robin Schreiber
|
||||
Chad J. Schroeder
|
||||
|
|
|
@ -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 @@ date_local_from_object(PyObject *cls, PyObject *obj)
|
|||
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 @@ datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
|||
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 @@ local(long long u)
|
|||
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 @@ datetime_from_timet_and_us(PyObject *cls, TM_FUNC f, time_t timet, int us,
|
|||
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 @@ datetime_from_timet_and_us(PyObject *cls, TM_FUNC f, time_t timet, int us,
|
|||
*/
|
||||
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 @@ datetime_datetime_now_impl(PyTypeObject *type, PyObject *tz)
|
|||
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 @@ datetime_datetime_now_impl(PyTypeObject *type, PyObject *tz)
|
|||
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 @@ datetime_fromtimestamp(PyObject *cls, PyObject *args, PyObject *kw)
|
|||
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 @@ datetime_utcfromtimestamp(PyObject *cls, PyObject *args)
|
|||
PyObject *result = NULL;
|
||||
|
||||
if (PyArg_ParseTuple(args, "O:utcfromtimestamp", ×tamp))
|
||||
result = datetime_from_timestamp(cls, gmtime_r, timestamp,
|
||||
result = datetime_from_timestamp(cls, _PyTime_gmtime, timestamp,
|
||||
Py_None);
|
||||
return result;
|
||||
}
|
||||
|
@ -5040,14 +5017,8 @@ local_timezone_from_timestamp(time_t timestamp)
|
|||
PyObject *nameo = NULL;
|
||||
const char *zone = NULL;
|
||||
|
||||
if (localtime_r(×tamp, &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 @@ local_timezone_from_timestamp(time_t timestamp)
|
|||
if (local_time == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (gmtime_r(×tamp, &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,
|
||||
|
|
|
@ -343,21 +343,14 @@ static PyObject *
|
|||
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 @@ GMT). When 'seconds' is not passed in, convert the current time instead.\n\
|
|||
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 @@ time_localtime(PyObject *self, PyObject *args)
|
|||
|
||||
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 @@ time_strftime(PyObject *self, PyObject *args)
|
|||
|
||||
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 @@ time_asctime(PyObject *self, PyObject *args)
|
|||
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 @@ time_ctime(PyObject *self, PyObject *args)
|
|||
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 @@ PyInit_timezone(PyObject *m) {
|
|||
{
|
||||
#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 ) {
|
||||
|
|
|
@ -766,3 +766,55 @@ _PyTime_Init(void)
|
|||
|
||||
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 */
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue