]> granicus.if.org Git - python/commitdiff
Issue #8644: Improve accuracy of timedelta.total_seconds method.
authorMark Dickinson <dickinsm@gmail.com>
Sun, 9 May 2010 09:30:06 +0000 (09:30 +0000)
committerMark Dickinson <dickinsm@gmail.com>
Sun, 9 May 2010 09:30:06 +0000 (09:30 +0000)
(Backport of r80979 to py3k.)  Thanks Alexander Belopolsky.

Doc/library/datetime.rst
Lib/test/test_datetime.py
Misc/NEWS
Modules/datetimemodule.c

index 16429de5b68a60d33558d3c47db1a1ebcafa4166..d612e8731c7ca126b677484a3038a489d16002aa 100644 (file)
@@ -270,8 +270,12 @@ 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``.
+   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 52387a09e93184a4ca1c2c7f8b402342fbc2df57..4715ce123a990ecf2596c9fd6d7c2537cdcf60aa 100644 (file)
@@ -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 @@ 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(),
+                             ((24*3600*td.days + td.seconds)*10**6
+                              + td.microseconds)/10**6)
 
     def test_carries(self):
         t1 = timedelta(days=100,
index ac28fadc6d8eda22123b38710923fb21c67a17c2..6536dcc6fe3786d8b46e20f3f4a08dbc408413f0 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -200,6 +200,8 @@ Library
 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 fa7ef0b71b32a40c91c9e1c42d9a2f85e7ecfea1..7105c6935d4db28b1ea72f6676ce956a79c02717 100644 (file)
@@ -2096,9 +2096,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 *