|
|
|
@ -35,6 +35,13 @@ error_time_t_overflow(void) |
|
|
|
"timestamp out of range for platform time_t"); |
|
|
|
} |
|
|
|
|
|
|
|
static void |
|
|
|
_PyTime_overflow(void) |
|
|
|
{ |
|
|
|
PyErr_SetString(PyExc_OverflowError, |
|
|
|
"timestamp too large to convert to C _PyTime_t"); |
|
|
|
} |
|
|
|
|
|
|
|
time_t |
|
|
|
_PyLong_AsTime_t(PyObject *obj) |
|
|
|
{ |
|
|
|
@ -47,8 +54,9 @@ _PyLong_AsTime_t(PyObject *obj) |
|
|
|
val = PyLong_AsLong(obj); |
|
|
|
#endif |
|
|
|
if (val == -1 && PyErr_Occurred()) { |
|
|
|
if (PyErr_ExceptionMatches(PyExc_OverflowError)) |
|
|
|
if (PyErr_ExceptionMatches(PyExc_OverflowError)) { |
|
|
|
error_time_t_overflow(); |
|
|
|
} |
|
|
|
return -1; |
|
|
|
} |
|
|
|
return (time_t)val; |
|
|
|
@ -71,9 +79,10 @@ static double |
|
|
|
_PyTime_RoundHalfEven(double x) |
|
|
|
{ |
|
|
|
double rounded = round(x); |
|
|
|
if (fabs(x-rounded) == 0.5) |
|
|
|
if (fabs(x-rounded) == 0.5) { |
|
|
|
/* halfway case: round to even */ |
|
|
|
rounded = 2.0*round(x/2.0); |
|
|
|
} |
|
|
|
return rounded; |
|
|
|
} |
|
|
|
|
|
|
|
@ -84,19 +93,23 @@ _PyTime_Round(double x, _PyTime_round_t round) |
|
|
|
volatile double d; |
|
|
|
|
|
|
|
d = x; |
|
|
|
if (round == _PyTime_ROUND_HALF_EVEN) |
|
|
|
if (round == _PyTime_ROUND_HALF_EVEN) { |
|
|
|
d = _PyTime_RoundHalfEven(d); |
|
|
|
else if (round == _PyTime_ROUND_CEILING) |
|
|
|
} |
|
|
|
else if (round == _PyTime_ROUND_CEILING) { |
|
|
|
d = ceil(d); |
|
|
|
else |
|
|
|
} |
|
|
|
else { |
|
|
|
d = floor(d); |
|
|
|
} |
|
|
|
return d; |
|
|
|
} |
|
|
|
|
|
|
|
static int |
|
|
|
_PyTime_DoubleToDenominator(double d, time_t *sec, long *numerator, |
|
|
|
double denominator, _PyTime_round_t round) |
|
|
|
long idenominator, _PyTime_round_t round) |
|
|
|
{ |
|
|
|
double denominator = (double)idenominator; |
|
|
|
double intpart; |
|
|
|
/* volatile avoids optimization changing how numbers are rounded */ |
|
|
|
volatile double floatpart; |
|
|
|
@ -121,15 +134,15 @@ _PyTime_DoubleToDenominator(double d, time_t *sec, long *numerator, |
|
|
|
} |
|
|
|
*sec = (time_t)intpart; |
|
|
|
*numerator = (long)floatpart; |
|
|
|
|
|
|
|
assert(0 <= *numerator && *numerator < idenominator); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int |
|
|
|
_PyTime_ObjectToDenominator(PyObject *obj, time_t *sec, long *numerator, |
|
|
|
double denominator, _PyTime_round_t round) |
|
|
|
long denominator, _PyTime_round_t round) |
|
|
|
{ |
|
|
|
assert(denominator <= (double)LONG_MAX); |
|
|
|
assert(denominator >= 1); |
|
|
|
|
|
|
|
if (PyFloat_Check(obj)) { |
|
|
|
double d = PyFloat_AsDouble(obj); |
|
|
|
@ -144,8 +157,9 @@ _PyTime_ObjectToDenominator(PyObject *obj, time_t *sec, long *numerator, |
|
|
|
else { |
|
|
|
*sec = _PyLong_AsTime_t(obj); |
|
|
|
*numerator = 0; |
|
|
|
if (*sec == (time_t)-1 && PyErr_Occurred()) |
|
|
|
if (*sec == (time_t)-1 && PyErr_Occurred()) { |
|
|
|
return -1; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -176,8 +190,9 @@ _PyTime_ObjectToTime_t(PyObject *obj, time_t *sec, _PyTime_round_t round) |
|
|
|
} |
|
|
|
else { |
|
|
|
*sec = _PyLong_AsTime_t(obj); |
|
|
|
if (*sec == (time_t)-1 && PyErr_Occurred()) |
|
|
|
if (*sec == (time_t)-1 && PyErr_Occurred()) { |
|
|
|
return -1; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -186,43 +201,27 @@ int |
|
|
|
_PyTime_ObjectToTimespec(PyObject *obj, time_t *sec, long *nsec, |
|
|
|
_PyTime_round_t round) |
|
|
|
{ |
|
|
|
int res; |
|
|
|
res = _PyTime_ObjectToDenominator(obj, sec, nsec, 1e9, round); |
|
|
|
if (res == 0) { |
|
|
|
assert(0 <= *nsec && *nsec < SEC_TO_NS); |
|
|
|
} |
|
|
|
return res; |
|
|
|
return _PyTime_ObjectToDenominator(obj, sec, nsec, SEC_TO_NS, round); |
|
|
|
} |
|
|
|
|
|
|
|
int |
|
|
|
_PyTime_ObjectToTimeval(PyObject *obj, time_t *sec, long *usec, |
|
|
|
_PyTime_round_t round) |
|
|
|
{ |
|
|
|
int res; |
|
|
|
res = _PyTime_ObjectToDenominator(obj, sec, usec, 1e6, round); |
|
|
|
if (res == 0) { |
|
|
|
assert(0 <= *usec && *usec < SEC_TO_US); |
|
|
|
} |
|
|
|
return res; |
|
|
|
} |
|
|
|
|
|
|
|
static void |
|
|
|
_PyTime_overflow(void) |
|
|
|
{ |
|
|
|
PyErr_SetString(PyExc_OverflowError, |
|
|
|
"timestamp too large to convert to C _PyTime_t"); |
|
|
|
return _PyTime_ObjectToDenominator(obj, sec, usec, SEC_TO_US, round); |
|
|
|
} |
|
|
|
|
|
|
|
_PyTime_t |
|
|
|
_PyTime_FromSeconds(int seconds) |
|
|
|
{ |
|
|
|
_PyTime_t t; |
|
|
|
t = (_PyTime_t)seconds; |
|
|
|
/* ensure that integer overflow cannot happen, int type should have 32 |
|
|
|
bits, whereas _PyTime_t type has at least 64 bits (SEC_TO_MS takes 30 |
|
|
|
bits). */ |
|
|
|
Py_BUILD_ASSERT(INT_MAX <= _PyTime_MAX / SEC_TO_NS); |
|
|
|
Py_BUILD_ASSERT(INT_MIN >= _PyTime_MIN / SEC_TO_NS); |
|
|
|
|
|
|
|
t = (_PyTime_t)seconds; |
|
|
|
assert((t >= 0 && t <= _PyTime_MAX / SEC_TO_NS) |
|
|
|
|| (t < 0 && t >= _PyTime_MIN / SEC_TO_NS)); |
|
|
|
t *= SEC_TO_NS; |
|
|
|
@ -249,8 +248,9 @@ _PyTime_FromTimespec(_PyTime_t *tp, struct timespec *ts, int raise) |
|
|
|
t = (_PyTime_t)ts->tv_sec; |
|
|
|
|
|
|
|
if (_PyTime_check_mul_overflow(t, SEC_TO_NS)) { |
|
|
|
if (raise) |
|
|
|
if (raise) { |
|
|
|
_PyTime_overflow(); |
|
|
|
} |
|
|
|
res = -1; |
|
|
|
} |
|
|
|
t = t * SEC_TO_NS; |
|
|
|
@ -271,8 +271,9 @@ _PyTime_FromTimeval(_PyTime_t *tp, struct timeval *tv, int raise) |
|
|
|
t = (_PyTime_t)tv->tv_sec; |
|
|
|
|
|
|
|
if (_PyTime_check_mul_overflow(t, SEC_TO_NS)) { |
|
|
|
if (raise) |
|
|
|
if (raise) { |
|
|
|
_PyTime_overflow(); |
|
|
|
} |
|
|
|
res = -1; |
|
|
|
} |
|
|
|
t = t * SEC_TO_NS; |
|
|
|
@ -323,8 +324,9 @@ _PyTime_FromObject(_PyTime_t *t, PyObject *obj, _PyTime_round_t round, |
|
|
|
|
|
|
|
sec = PyLong_AsLongLong(obj); |
|
|
|
if (sec == -1 && PyErr_Occurred()) { |
|
|
|
if (PyErr_ExceptionMatches(PyExc_OverflowError)) |
|
|
|
if (PyErr_ExceptionMatches(PyExc_OverflowError)) { |
|
|
|
_PyTime_overflow(); |
|
|
|
} |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
@ -387,24 +389,30 @@ _PyTime_Divide(const _PyTime_t t, const _PyTime_t k, |
|
|
|
r = t % k; |
|
|
|
abs_r = Py_ABS(r); |
|
|
|
if (abs_r > k / 2 || (abs_r == k / 2 && (Py_ABS(x) & 1))) { |
|
|
|
if (t >= 0) |
|
|
|
if (t >= 0) { |
|
|
|
x++; |
|
|
|
else |
|
|
|
} |
|
|
|
else { |
|
|
|
x--; |
|
|
|
} |
|
|
|
} |
|
|
|
return x; |
|
|
|
} |
|
|
|
else if (round == _PyTime_ROUND_CEILING) { |
|
|
|
if (t >= 0) |
|
|
|
if (t >= 0) { |
|
|
|
return (t + k - 1) / k; |
|
|
|
else |
|
|
|
} |
|
|
|
else { |
|
|
|
return t / k; |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
if (t >= 0) |
|
|
|
if (t >= 0) { |
|
|
|
return t / k; |
|
|
|
else |
|
|
|
} |
|
|
|
else { |
|
|
|
return (t - (k - 1)) / k; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -434,17 +442,21 @@ _PyTime_AsTimeval_impl(_PyTime_t t, _PyTime_t *p_secs, int *p_us, |
|
|
|
usec = (int)_PyTime_Divide(ns, US_TO_NS, round); |
|
|
|
if (usec < 0) { |
|
|
|
usec += SEC_TO_US; |
|
|
|
if (secs != _PyTime_MIN) |
|
|
|
if (secs != _PyTime_MIN) { |
|
|
|
secs -= 1; |
|
|
|
else |
|
|
|
} |
|
|
|
else { |
|
|
|
res = -1; |
|
|
|
} |
|
|
|
} |
|
|
|
else if (usec >= SEC_TO_US) { |
|
|
|
usec -= SEC_TO_US; |
|
|
|
if (secs != _PyTime_MAX) |
|
|
|
if (secs != _PyTime_MAX) { |
|
|
|
secs += 1; |
|
|
|
else |
|
|
|
} |
|
|
|
else { |
|
|
|
res = -1; |
|
|
|
} |
|
|
|
} |
|
|
|
assert(0 <= usec && usec < SEC_TO_US); |
|
|
|
|
|
|
|
@ -473,8 +485,9 @@ _PyTime_AsTimevalStruct_impl(_PyTime_t t, struct timeval *tv, |
|
|
|
|
|
|
|
secs2 = (_PyTime_t)tv->tv_sec; |
|
|
|
if (res < 0 || secs2 != secs) { |
|
|
|
if (raise) |
|
|
|
if (raise) { |
|
|
|
error_time_t_overflow(); |
|
|
|
} |
|
|
|
return -1; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
@ -580,22 +593,26 @@ pygettimeofday(_PyTime_t *tp, _Py_clock_info_t *info, int raise) |
|
|
|
#ifdef HAVE_CLOCK_GETTIME |
|
|
|
err = clock_gettime(CLOCK_REALTIME, &ts); |
|
|
|
if (err) { |
|
|
|
if (raise) |
|
|
|
if (raise) { |
|
|
|
PyErr_SetFromErrno(PyExc_OSError); |
|
|
|
} |
|
|
|
return -1; |
|
|
|
} |
|
|
|
if (_PyTime_FromTimespec(tp, &ts, raise) < 0) |
|
|
|
if (_PyTime_FromTimespec(tp, &ts, raise) < 0) { |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
if (info) { |
|
|
|
struct timespec res; |
|
|
|
info->implementation = "clock_gettime(CLOCK_REALTIME)"; |
|
|
|
info->monotonic = 0; |
|
|
|
info->adjustable = 1; |
|
|
|
if (clock_getres(CLOCK_REALTIME, &res) == 0) |
|
|
|
if (clock_getres(CLOCK_REALTIME, &res) == 0) { |
|
|
|
info->resolution = res.tv_sec + res.tv_nsec * 1e-9; |
|
|
|
else |
|
|
|
} |
|
|
|
else { |
|
|
|
info->resolution = 1e-9; |
|
|
|
} |
|
|
|
} |
|
|
|
#else /* HAVE_CLOCK_GETTIME */ |
|
|
|
|
|
|
|
@ -606,12 +623,14 @@ pygettimeofday(_PyTime_t *tp, _Py_clock_info_t *info, int raise) |
|
|
|
err = gettimeofday(&tv, (struct timezone *)NULL); |
|
|
|
#endif |
|
|
|
if (err) { |
|
|
|
if (raise) |
|
|
|
if (raise) { |
|
|
|
PyErr_SetFromErrno(PyExc_OSError); |
|
|
|
} |
|
|
|
return -1; |
|
|
|
} |
|
|
|
if (_PyTime_FromTimeval(tp, &tv, raise) < 0) |
|
|
|
if (_PyTime_FromTimeval(tp, &tv, raise) < 0) { |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
if (info) { |
|
|
|
info->implementation = "gettimeofday()"; |
|
|
|
@ -755,8 +774,9 @@ pymonotonic(_PyTime_t *tp, _Py_clock_info_t *info, int raise) |
|
|
|
} |
|
|
|
info->resolution = res.tv_sec + res.tv_nsec * 1e-9; |
|
|
|
} |
|
|
|
if (_PyTime_FromTimespec(tp, &ts, raise) < 0) |
|
|
|
if (_PyTime_FromTimespec(tp, &ts, raise) < 0) { |
|
|
|
return -1; |
|
|
|
} |
|
|
|
#endif |
|
|
|
return 0; |
|
|
|
} |
|
|
|
@ -872,8 +892,9 @@ _PyTime_localtime(time_t t, struct tm *tm) |
|
|
|
#else /* !MS_WINDOWS */ |
|
|
|
if (localtime_r(&t, tm) == NULL) { |
|
|
|
#ifdef EINVAL |
|
|
|
if (errno == 0) |
|
|
|
if (errno == 0) { |
|
|
|
errno = EINVAL; |
|
|
|
} |
|
|
|
#endif |
|
|
|
PyErr_SetFromErrno(PyExc_OSError); |
|
|
|
return -1; |
|
|
|
@ -898,8 +919,9 @@ _PyTime_gmtime(time_t t, struct tm *tm) |
|
|
|
#else /* !MS_WINDOWS */ |
|
|
|
if (gmtime_r(&t, tm) == NULL) { |
|
|
|
#ifdef EINVAL |
|
|
|
if (errno == 0) |
|
|
|
if (errno == 0) { |
|
|
|
errno = EINVAL; |
|
|
|
} |
|
|
|
#endif |
|
|
|
PyErr_SetFromErrno(PyExc_OSError); |
|
|
|
return -1; |
|
|
|
|