Index: Misc/NEWS =================================================================== --- Misc/NEWS (revision 81011) +++ Misc/NEWS (working copy) @@ -70,6 +70,8 @@ inheritance with the underlying socket object. The cheap inheritance has been deprecated. +- Issue #8644: td.total_seconds() is now equivalent to td / timedelta(seconds=1). + - Issue #4265: shutil.copyfile() was leaking file descriptors when disk fills. Patch by Tres Seaver. @@ -200,6 +202,8 @@ Extension Modules ----------------- +- Issue #8644: Improved accuracy of timedelta.total_seconds(). + - Use Clang 2.7's static analyzer to find places to clean up some code. - Build the ossaudio extension on GNU/kFreeBSD. Index: Doc/library/datetime.rst =================================================================== --- Doc/library/datetime.rst (revision 81011) +++ Doc/library/datetime.rst (working copy) @@ -270,9 +270,13 @@ .. 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``. + Return the total number of seconds contained in the duration. + Equivalent to ``(td.microseconds + (td.seconds + td.days * 24 * + 3600) * 10**6) / 10**6`` computed with true division enabled. + Note that for very large time intervals (greater than 270 years on + most platforms) this method will lose microsecond accuracy. + .. versionadded:: 2.7 Index: Lib/test/test_datetime.py =================================================================== --- Lib/test/test_datetime.py (revision 81011) +++ Lib/test/test_datetime.py (working copy) @@ -2,7 +2,7 @@ See http://www.zope.org/Members/fdrake/DateTimeWiki/TestCases """ - +from __future__ import division import os import pickle import cPickle @@ -269,6 +269,13 @@ 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(), + ((24*3600*td.days + td.seconds)*10**6 + + td.microseconds)/10**6) def test_carries(self): t1 = timedelta(days=100, Index: Modules/datetimemodule.c =================================================================== --- Modules/datetimemodule.c (revision 81011) +++ Modules/datetimemodule.c (working copy) @@ -2096,9 +2096,25 @@ 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 *