Issue #8644: Improve accuracy of timedelta.total_seconds, by doing intermediate
computations with integer arithmetic instead of floating point. td.total_seconds() now agrees with td / timedelta(seconds = 1). Thanks Alexander Belopolsky for the patch.
This commit is contained in:
parent
161b024b6d
commit
0381e3f16a
|
@ -287,7 +287,10 @@ Instance methods:
|
|||
.. method:: timedelta.total_seconds()
|
||||
|
||||
Return the total number of seconds contained in the duration. Equivalent to
|
||||
``td.microseconds / 1000000 + td.seconds + td.days * 24 * 3600``.
|
||||
``td / timedelta(seconds=1)``.
|
||||
|
||||
Note that for very large time intervals (greater than 270 years on
|
||||
most platforms) this method will lose microsecond accuracy.
|
||||
|
||||
.. versionadded:: 3.2
|
||||
|
||||
|
|
|
@ -264,6 +264,11 @@ class TestTimeDelta(HarmlessMixedComparison, unittest.TestCase):
|
|||
for total_seconds in [123456.789012, -123456.789012, 0.123456, 0, 1e6]:
|
||||
td = timedelta(seconds=total_seconds)
|
||||
self.assertEqual(td.total_seconds(), total_seconds)
|
||||
# Issue8644: Test that td.total_seconds() has the same
|
||||
# accuracy as td / timedelta(seconds=1).
|
||||
for ms in [-1, -2, -123]:
|
||||
td = timedelta(microseconds=ms)
|
||||
self.assertEqual(td.total_seconds(), td / timedelta(seconds=1))
|
||||
|
||||
def test_carries(self):
|
||||
t1 = timedelta(days=100,
|
||||
|
|
|
@ -1105,6 +1105,11 @@ Library
|
|||
Extension Modules
|
||||
-----------------
|
||||
|
||||
- Issue #8644: The accuracy of td.total_seconds() has been improved (by
|
||||
calculating with integer arithmetic instead of float arithmetic internally):
|
||||
the result is now always correctly rounded, and is equivalent to td /
|
||||
timedelta(seconds=1).
|
||||
|
||||
- Issue #2706: Allow division of a timedelta by another timedelta:
|
||||
timedelta / timedelta, timedelta % timedelta, timedelta // timedelta
|
||||
and divmod(timedelta, timedelta) are all supported.
|
||||
|
|
|
@ -2211,9 +2211,25 @@ delta_getstate(PyDateTime_Delta *self)
|
|||
static PyObject *
|
||||
delta_total_seconds(PyObject *self)
|
||||
{
|
||||
return PyFloat_FromDouble(GET_TD_MICROSECONDS(self) / 1000000.0 +
|
||||
GET_TD_SECONDS(self) +
|
||||
GET_TD_DAYS(self) * 24.0 * 3600.0);
|
||||
PyObject *total_seconds;
|
||||
PyObject *total_microseconds;
|
||||
PyObject *one_million;
|
||||
|
||||
total_microseconds = delta_to_microseconds((PyDateTime_Delta *)self);
|
||||
if (total_microseconds == NULL)
|
||||
return NULL;
|
||||
|
||||
one_million = PyLong_FromLong(1000000L);
|
||||
if (one_million == NULL) {
|
||||
Py_DECREF(total_microseconds);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
total_seconds = PyNumber_TrueDivide(total_microseconds, one_million);
|
||||
|
||||
Py_DECREF(total_microseconds);
|
||||
Py_DECREF(one_million);
|
||||
return total_seconds;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
|
Loading…
Reference in New Issue