diff options
| author | Victor Stinner <victor.stinner@gmail.com> | 2015-09-18 13:36:17 +0200 | 
|---|---|---|
| committer | Victor Stinner <victor.stinner@gmail.com> | 2015-09-18 13:36:17 +0200 | 
| commit | 9a8b177e60cc5cc6d5105519c0df8fb185211e1d (patch) | |
| tree | 83036f077d2267d3c60f172242de4ee8892a5323 /Python/pytime.c | |
| parent | 4b352171d2b0a4a63cd711df9ebe840419137fa2 (diff) | |
| download | cpython-git-9a8b177e60cc5cc6d5105519c0df8fb185211e1d.tar.gz | |
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.
Diffstat (limited to 'Python/pytime.c')
| -rw-r--r-- | Python/pytime.c | 99 | 
1 files changed, 61 insertions, 38 deletions
diff --git a/Python/pytime.c b/Python/pytime.c index 77db204489..85e1ca8388 100644 --- a/Python/pytime.c +++ b/Python/pytime.c @@ -331,69 +331,92 @@ _PyTime_AsMicroseconds(_PyTime_t t, _PyTime_round_t round)  }  static int -_PyTime_AsTimeval_impl(_PyTime_t t, struct timeval *tv, _PyTime_round_t round, -                       int raise) +_PyTime_AsTimeval_impl(_PyTime_t t, _PyTime_t *p_secs, int *p_us, +                       _PyTime_round_t round)  {      _PyTime_t secs, ns; +    int usec;      int res = 0;      secs = t / SEC_TO_NS;      ns = t % SEC_TO_NS; -    if (ns < 0) { -        ns += SEC_TO_NS; -        secs -= 1; -    } -#ifdef MS_WINDOWS -    /* On Windows, timeval.tv_sec is a long (32 bit), -       whereas time_t can be 64-bit. */ -    assert(sizeof(tv->tv_sec) == sizeof(long)); -#if SIZEOF_TIME_T > SIZEOF_LONG -    if (secs > LONG_MAX) { -        secs = LONG_MAX; -        res = -1; +    usec = (int)_PyTime_Divide(ns, US_TO_NS, round); +    if (usec < 0) { +        usec += SEC_TO_US; +        if (secs != _PyTime_MIN) +            secs -= 1; +        else +            res = -1;      } -    else if (secs < LONG_MIN) { -        secs = LONG_MIN; -        res = -1; +    else if (usec >= SEC_TO_US) { +        usec -= SEC_TO_US; +        if (secs != _PyTime_MAX) +            secs += 1; +        else +            res = -1;      } -#endif +    assert(0 <= usec && usec < SEC_TO_US); + +    *p_secs = secs; +    *p_us = usec; + +    return res; +} + +static int +_PyTime_AsTimevalStruct_impl(_PyTime_t t, struct timeval *tv, +                             _PyTime_round_t round, int raise) +{ +    _PyTime_t secs; +    int us; +    int res; + +    res = _PyTime_AsTimeval_impl(t, &secs, &us, round); + +#ifdef MS_WINDOWS      tv->tv_sec = (long)secs;  #else -    /* On OpenBSD 5.4, timeval.tv_sec is a long. -       Example: long is 64-bit, whereas time_t is 32-bit. */      tv->tv_sec = secs; -    if ((_PyTime_t)tv->tv_sec != secs) -        res = -1;  #endif +    tv->tv_usec = us; -    if (round == _PyTime_ROUND_CEILING) -        tv->tv_usec = (int)((ns + US_TO_NS - 1) / US_TO_NS); -    else -        tv->tv_usec = (int)(ns / US_TO_NS); - -    if (tv->tv_usec >= SEC_TO_US) { -        tv->tv_usec -= SEC_TO_US; -        tv->tv_sec += 1; +    if (res < 0 || (_PyTime_t)tv->tv_sec != secs) { +        if (raise) +            error_time_t_overflow(); +        return -1;      } - -    if (res && raise) -        _PyTime_overflow(); - -    assert(0 <= tv->tv_usec && tv->tv_usec <= 999999); -    return res; +    return 0;  }  int  _PyTime_AsTimeval(_PyTime_t t, struct timeval *tv, _PyTime_round_t round)  { -    return _PyTime_AsTimeval_impl(t, tv, round, 1); +    return _PyTime_AsTimevalStruct_impl(t, tv, round, 1);  }  int  _PyTime_AsTimeval_noraise(_PyTime_t t, struct timeval *tv, _PyTime_round_t round)  { -    return _PyTime_AsTimeval_impl(t, tv, round, 0); +    return _PyTime_AsTimevalStruct_impl(t, tv, round, 0); +} + +int +_PyTime_AsTimevalTime_t(_PyTime_t t, time_t *p_secs, int *us, +                        _PyTime_round_t round) +{ +    _PyTime_t secs; +    int res; + +    res = _PyTime_AsTimeval_impl(t, &secs, us, round); + +    *p_secs = secs; + +    if (res < 0 || (_PyTime_t)*p_secs != secs) { +        error_time_t_overflow(); +        return -1; +    } +    return 0;  }  #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_KQUEUE)  | 
