summaryrefslogtreecommitdiffstats
path: root/Lib/datetime.py
diff options
context:
space:
mode:
authorAlexander Belopolsky <alexander.belopolsky@gmail.com>2015-02-28 15:44:47 (GMT)
committerAlexander Belopolsky <alexander.belopolsky@gmail.com>2015-02-28 15:44:47 (GMT)
commit184291aeb74249e644b3df581d240811e4b8a6e2 (patch)
tree2a75bb0cc749c5e0dace84b712f1604d1256daf9 /Lib/datetime.py
parent6ab0ec935260247640fd963f29e446238fb436bd (diff)
parent24d3deefcf2f78b12fc29ed4c9a3811d46c534bb (diff)
downloadcpython-184291aeb74249e644b3df581d240811e4b8a6e2.zip
cpython-184291aeb74249e644b3df581d240811e4b8a6e2.tar.gz
cpython-184291aeb74249e644b3df581d240811e4b8a6e2.tar.bz2
Fixes #23521: Corrected pure python implementation of timedelta division.
* Eliminated OverflowError from timedelta * float for some floats; * Corrected rounding in timedlta true division.
Diffstat (limited to 'Lib/datetime.py')
-rw-r--r--Lib/datetime.py26
1 files changed, 23 insertions, 3 deletions
diff --git a/Lib/datetime.py b/Lib/datetime.py
index 4afe9a5..2768e9b 100644
--- a/Lib/datetime.py
+++ b/Lib/datetime.py
@@ -297,6 +297,25 @@ def _cmperror(x, y):
raise TypeError("can't compare '%s' to '%s'" % (
type(x).__name__, type(y).__name__))
+def _divide_and_round(a, b):
+ """divide a by b and round result to the nearest integer
+
+ When the ratio is exactly half-way between two integers,
+ the even integer is returned.
+ """
+ # Based on the reference implementation for divmod_near
+ # in Objects/longobject.c.
+ q, r = divmod(a, b)
+ # round up if either r / b > 0.5, or r / b == 0.5 and q is odd.
+ # The expression r / b > 0.5 is equivalent to 2 * r > b if b is
+ # positive, 2 * r < b if b negative.
+ r *= 2
+ greater_than_half = r > b if b > 0 else r < b
+ if greater_than_half or r == b and q % 2 == 1:
+ q += 1
+
+ return q
+
class timedelta:
"""Represent the difference between two datetime objects.
@@ -515,8 +534,9 @@ class timedelta:
self._seconds * other,
self._microseconds * other)
if isinstance(other, float):
+ usec = self._to_microseconds()
a, b = other.as_integer_ratio()
- return self * a / b
+ return timedelta(0, 0, _divide_and_round(usec * a, b))
return NotImplemented
__rmul__ = __mul__
@@ -541,10 +561,10 @@ class timedelta:
if isinstance(other, timedelta):
return usec / other._to_microseconds()
if isinstance(other, int):
- return timedelta(0, 0, usec / other)
+ return timedelta(0, 0, _divide_and_round(usec, other))
if isinstance(other, float):
a, b = other.as_integer_ratio()
- return timedelta(0, 0, b * usec / a)
+ return timedelta(0, 0, _divide_and_round(b * usec, a))
def __mod__(self, other):
if isinstance(other, timedelta):