Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1e2b688

Browse files
committed
Issue #25155: Add _PyTime_AsTimevalTime_t() function
On Windows, the tv_sec field of the timeval structure has the type C long, whereas it has the type C time_t on all other platforms. A C long has a size of 32 bits (signed inter, 1 bit for the sign, 31 bits for the value) which is not enough to store an Epoch timestamp after the year 2038. Add the _PyTime_AsTimevalTime_t() function written for datetime.datetime.now(): convert a _PyTime_t timestamp to a (secs, us) tuple where secs type is time_t. It allows to support dates after the year 2038 on Windows. Enhance also _PyTime_AsTimeval_impl() to detect overflow on the number of seconds when rounding the number of microseconds.
1 parent 1bd0b54 commit 1e2b688

3 files changed

Lines changed: 77 additions & 23 deletions

File tree

Include/pytime.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,18 @@ PyAPI_FUNC(int) _PyTime_AsTimeval_noraise(_PyTime_t t,
120120
struct timeval *tv,
121121
_PyTime_round_t round);
122122

123+
/* Convert a timestamp to a number of seconds (secs) and microseconds (us).
124+
us is always positive. This function is similar to _PyTime_AsTimeval()
125+
except that secs is always a time_t type, whereas the timeval structure
126+
uses a C long for tv_sec on Windows.
127+
Raise an exception and return -1 if the conversion overflowed,
128+
return 0 on success. */
129+
PyAPI_FUNC(int) _PyTime_AsTimevalTime_t(
130+
_PyTime_t t,
131+
time_t *secs,
132+
int *us,
133+
_PyTime_round_t round);
134+
123135
#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_KQUEUE)
124136
/* Convert a timestamp to a timespec structure (nanosecond resolution).
125137
tv_nsec is always positive.

Modules/_datetimemodule.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4117,13 +4117,14 @@ static PyObject *
41174117
datetime_best_possible(PyObject *cls, TM_FUNC f, PyObject *tzinfo)
41184118
{
41194119
_PyTime_t ts = _PyTime_GetSystemClock();
4120-
struct timeval tv;
4120+
time_t secs;
4121+
int us;
41214122

4122-
if (_PyTime_AsTimeval(ts, &tv, _PyTime_ROUND_FLOOR) < 0)
4123+
if (_PyTime_AsTimevalTime_t(ts, &secs, &us, _PyTime_ROUND_FLOOR) < 0)
41234124
return NULL;
4124-
assert(0 <= tv.tv_usec && tv.tv_usec <= 999999);
4125+
assert(0 <= us && us <= 999999);
41254126

4126-
return datetime_from_timet_and_us(cls, f, tv.tv_sec, tv.tv_usec, tzinfo);
4127+
return datetime_from_timet_and_us(cls, f, secs, us, tzinfo);
41274128
}
41284129

41294130
/*[clinic input]

Python/pytime.c

Lines changed: 60 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -417,54 +417,95 @@ _PyTime_AsMicroseconds(_PyTime_t t, _PyTime_round_t round)
417417
}
418418

419419
static int
420-
_PyTime_AsTimeval_impl(_PyTime_t t, struct timeval *tv, _PyTime_round_t round,
421-
int raise)
420+
_PyTime_AsTimeval_impl(_PyTime_t t, _PyTime_t *p_secs, int *p_us,
421+
_PyTime_round_t round)
422422
{
423423
_PyTime_t secs, ns;
424-
int res = 0;
425424
int usec;
425+
int res = 0;
426426

427427
secs = t / SEC_TO_NS;
428428
ns = t % SEC_TO_NS;
429429

430-
#ifdef MS_WINDOWS
431-
tv->tv_sec = (long)secs;
432-
#else
433-
tv->tv_sec = secs;
434-
#endif
435-
if ((_PyTime_t)tv->tv_sec != secs)
436-
res = -1;
437-
438430
usec = (int)_PyTime_Divide(ns, US_TO_NS, round);
439431
if (usec < 0) {
440432
usec += SEC_TO_US;
441-
tv->tv_sec -= 1;
433+
if (secs != _PyTime_MIN)
434+
secs -= 1;
435+
else
436+
res = -1;
442437
}
443438
else if (usec >= SEC_TO_US) {
444439
usec -= SEC_TO_US;
445-
tv->tv_sec += 1;
440+
if (secs != _PyTime_MAX)
441+
secs += 1;
442+
else
443+
res = -1;
446444
}
447-
448445
assert(0 <= usec && usec < SEC_TO_US);
449-
tv->tv_usec = usec;
450446

451-
if (res && raise)
452-
error_time_t_overflow();
447+
*p_secs = secs;
448+
*p_us = usec;
449+
453450
return res;
454451
}
455452

453+
static int
454+
_PyTime_AsTimevalStruct_impl(_PyTime_t t, struct timeval *tv,
455+
_PyTime_round_t round, int raise)
456+
{
457+
_PyTime_t secs;
458+
int us;
459+
int res;
460+
461+
res = _PyTime_AsTimeval_impl(t, &secs, &us, round);
462+
463+
#ifdef MS_WINDOWS
464+
tv->tv_sec = (long)secs;
465+
#else
466+
tv->tv_sec = secs;
467+
#endif
468+
tv->tv_usec = us;
469+
470+
if (res < 0 || (_PyTime_t)tv->tv_sec != secs) {
471+
if (raise)
472+
error_time_t_overflow();
473+
return -1;
474+
}
475+
return 0;
476+
}
477+
456478
int
457479
_PyTime_AsTimeval(_PyTime_t t, struct timeval *tv, _PyTime_round_t round)
458480
{
459-
return _PyTime_AsTimeval_impl(t, tv, round, 1);
481+
return _PyTime_AsTimevalStruct_impl(t, tv, round, 1);
460482
}
461483

462484
int
463485
_PyTime_AsTimeval_noraise(_PyTime_t t, struct timeval *tv, _PyTime_round_t round)
464486
{
465-
return _PyTime_AsTimeval_impl(t, tv, round, 0);
487+
return _PyTime_AsTimevalStruct_impl(t, tv, round, 0);
466488
}
467489

490+
int
491+
_PyTime_AsTimevalTime_t(_PyTime_t t, time_t *p_secs, int *us,
492+
_PyTime_round_t round)
493+
{
494+
_PyTime_t secs;
495+
int res;
496+
497+
res = _PyTime_AsTimeval_impl(t, &secs, us, round);
498+
499+
*p_secs = secs;
500+
501+
if (res < 0 || (_PyTime_t)*p_secs != secs) {
502+
error_time_t_overflow();
503+
return -1;
504+
}
505+
return 0;
506+
}
507+
508+
468509
#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_KQUEUE)
469510
int
470511
_PyTime_AsTimespec(_PyTime_t t, struct timespec *ts)

0 commit comments

Comments
 (0)