Issue #22117: Fix rounding and implement _PyTime_ROUND_FLOOR in:

- _PyTime_ObjectToTime_t()
- _PyTime_ObjectToTimespec()
- _PyTime_ObjectToTimeval()
This commit is contained in:
Victor Stinner 2015-03-30 00:44:06 +02:00
parent 1bd18ba9a7
commit f81f0f9c63
2 changed files with 22 additions and 26 deletions

View File

@ -647,13 +647,13 @@ class TestPytime(unittest.TestCase):
(1e-9, (0, 1), _PyTime.ROUND_DOWN), (1e-9, (0, 1), _PyTime.ROUND_DOWN),
(1e-10, (0, 0), _PyTime.ROUND_DOWN), (1e-10, (0, 0), _PyTime.ROUND_DOWN),
(-1e-9, (-1, 999999999), _PyTime.ROUND_DOWN), (-1e-9, (-1, 999999999), _PyTime.ROUND_DOWN),
(-1e-10, (-1, 999999999), _PyTime.ROUND_DOWN), (-1e-10, (0, 0), _PyTime.ROUND_DOWN),
(-1.2, (-2, 800000000), _PyTime.ROUND_DOWN), (-1.2, (-2, 800000000), _PyTime.ROUND_DOWN),
(0.9999999999, (0, 999999999), _PyTime.ROUND_DOWN), (0.9999999999, (0, 999999999), _PyTime.ROUND_DOWN),
(1.1234567890, (1, 123456789), _PyTime.ROUND_DOWN), (1.1234567890, (1, 123456789), _PyTime.ROUND_DOWN),
(1.1234567899, (1, 123456789), _PyTime.ROUND_DOWN), (1.1234567899, (1, 123456789), _PyTime.ROUND_DOWN),
(-1.1234567890, (-2, 876543211), _PyTime.ROUND_DOWN), (-1.1234567890, (-2, 876543211), _PyTime.ROUND_DOWN),
(-1.1234567891, (-2, 876543210), _PyTime.ROUND_DOWN), (-1.1234567891, (-2, 876543211), _PyTime.ROUND_DOWN),
# Round away from zero # Round away from zero
(0, (0, 0), _PyTime.ROUND_UP), (0, (0, 0), _PyTime.ROUND_UP),
(-1, (-1, 0), _PyTime.ROUND_UP), (-1, (-1, 0), _PyTime.ROUND_UP),

View File

@ -26,6 +26,14 @@ error_time_t_overflow(void)
"timestamp out of range for platform time_t"); "timestamp out of range for platform time_t");
} }
static int
_PyTime_RoundTowardsPosInf(int is_neg, _PyTime_round_t round)
{
if (round == _PyTime_ROUND_FLOOR)
return 0;
return ((round == _PyTime_ROUND_UP) ^ is_neg);
}
time_t time_t
_PyLong_AsTime_t(PyObject *obj) _PyLong_AsTime_t(PyObject *obj)
{ {
@ -74,8 +82,7 @@ _PyTime_ObjectToDenominator(PyObject *obj, time_t *sec, long *numerator,
} }
floatpart *= denominator; floatpart *= denominator;
if (round == _PyTime_ROUND_UP) { if (_PyTime_RoundTowardsPosInf(intpart < 0, round)) {
if (intpart >= 0) {
floatpart = ceil(floatpart); floatpart = ceil(floatpart);
if (floatpart >= denominator) { if (floatpart >= denominator) {
floatpart = 0.0; floatpart = 0.0;
@ -85,7 +92,6 @@ _PyTime_ObjectToDenominator(PyObject *obj, time_t *sec, long *numerator,
else { else {
floatpart = floor(floatpart); floatpart = floor(floatpart);
} }
}
*sec = (time_t)intpart; *sec = (time_t)intpart;
err = intpart - (double)*sec; err = intpart - (double)*sec;
@ -113,12 +119,10 @@ _PyTime_ObjectToTime_t(PyObject *obj, time_t *sec, _PyTime_round_t round)
double d, intpart, err; double d, intpart, err;
d = PyFloat_AsDouble(obj); d = PyFloat_AsDouble(obj);
if (round == _PyTime_ROUND_UP) { if (_PyTime_RoundTowardsPosInf(d < 0, round))
if (d >= 0)
d = ceil(d); d = ceil(d);
else else
d = floor(d); d = floor(d);
}
(void)modf(d, &intpart); (void)modf(d, &intpart);
*sec = (time_t)intpart; *sec = (time_t)intpart;
@ -158,14 +162,6 @@ _PyTime_overflow(void)
"timestamp too large to convert to C _PyTime_t"); "timestamp too large to convert to C _PyTime_t");
} }
int
_PyTime_RoundTowardsPosInf(int is_neg, _PyTime_round_t round)
{
if (round == _PyTime_ROUND_FLOOR)
return 0;
return ((round == _PyTime_ROUND_UP) ^ is_neg);
}
_PyTime_t _PyTime_t
_PyTime_FromNanoseconds(PY_LONG_LONG ns) _PyTime_FromNanoseconds(PY_LONG_LONG ns)
{ {