diff options
author | Alexander Belopolsky <alexander.belopolsky@gmail.com> | 2015-02-28 15:41:57 (GMT) |
---|---|---|
committer | Alexander Belopolsky <alexander.belopolsky@gmail.com> | 2015-02-28 15:41:57 (GMT) |
commit | 24d3deefcf2f78b12fc29ed4c9a3811d46c534bb (patch) | |
tree | b5f0821a0f1f9bdef43fc1163b821f1a9c7ad7fb /Lib/datetime.py | |
parent | cf265fd02a0daacfa026b774a6eb2d7732b544a4 (diff) | |
download | cpython-24d3deefcf2f78b12fc29ed4c9a3811d46c534bb.zip cpython-24d3deefcf2f78b12fc29ed4c9a3811d46c534bb.tar.gz cpython-24d3deefcf2f78b12fc29ed4c9a3811d46c534bb.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.py | 26 |
1 files changed, 23 insertions, 3 deletions
diff --git a/Lib/datetime.py b/Lib/datetime.py index 1789714..4c442f2 100644 --- a/Lib/datetime.py +++ b/Lib/datetime.py @@ -280,6 +280,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. @@ -506,8 +525,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__ @@ -532,10 +552,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): |