From 2ec5bd6fb22ff71ffbe5987f55a31bc4177e39a6 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 3 Sep 2015 09:06:44 +0200 Subject: [PATCH] Issue #23517: fromtimestamp() and utcfromtimestamp() methods of datetime.datetime now round microseconds to nearest with ties going away from zero (ROUND_HALF_UP), as Python 2 and Python older than 3.3, instead of rounding towards -Infinity (ROUND_FLOOR). --- Lib/datetime.py | 4 ++-- Lib/test/datetimetester.py | 11 ++++++----- Misc/NEWS | 5 +++++ Modules/_datetimemodule.c | 2 +- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Lib/datetime.py b/Lib/datetime.py index d661460fa85..5ba2ddb7ab3 100644 --- a/Lib/datetime.py +++ b/Lib/datetime.py @@ -1384,7 +1384,7 @@ class datetime(date): converter = _time.localtime if tz is None else _time.gmtime t, frac = divmod(t, 1.0) - us = int(frac * 1e6) + us = _round_half_up(frac * 1e6) # If timestamp is less than one microsecond smaller than a # full second, us can be rounded up to 1000000. In this case, @@ -1404,7 +1404,7 @@ class datetime(date): def utcfromtimestamp(cls, t): """Construct a naive UTC datetime from a POSIX timestamp.""" t, frac = divmod(t, 1.0) - us = int(frac * 1e6) + us = _round_half_up(frac * 1e6) # If timestamp is less than one microsecond smaller than a # full second, us can be rounded up to 1000000. In this case, diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index 62f55272d9d..f516434bd6a 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -1847,6 +1847,7 @@ class TestDateTime(TestDate): zero = fts(0) self.assertEqual(zero.second, 0) self.assertEqual(zero.microsecond, 0) + one = fts(1e-6) try: minus_one = fts(-1e-6) except OSError: @@ -1857,22 +1858,22 @@ class TestDateTime(TestDate): self.assertEqual(minus_one.microsecond, 999999) t = fts(-1e-8) - self.assertEqual(t, minus_one) + self.assertEqual(t, zero) t = fts(-9e-7) self.assertEqual(t, minus_one) t = fts(-1e-7) - self.assertEqual(t, minus_one) + self.assertEqual(t, zero) t = fts(1e-7) self.assertEqual(t, zero) t = fts(9e-7) - self.assertEqual(t, zero) + self.assertEqual(t, one) t = fts(0.99999949) self.assertEqual(t.second, 0) self.assertEqual(t.microsecond, 999999) t = fts(0.9999999) - self.assertEqual(t.second, 0) - self.assertEqual(t.microsecond, 999999) + self.assertEqual(t.second, 1) + self.assertEqual(t.microsecond, 0) def test_insane_fromtimestamp(self): # It's possible that some platform maps time_t to double, diff --git a/Misc/NEWS b/Misc/NEWS index c9b925a0016..9af32ad1758 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -17,6 +17,11 @@ Core and Builtins Library ------- +- Issue #23517: fromtimestamp() and utcfromtimestamp() methods of + datetime.datetime now round microseconds to nearest with ties going away from + zero (ROUND_HALF_UP), as Python 2 and Python older than 3.3, instead of + rounding towards -Infinity (ROUND_FLOOR). + - Issue #23517: datetime.timedelta constructor now rounds microseconds to nearest with ties going away from zero (ROUND_HALF_UP), as Python 2 and Python older than 3.3, instead of rounding to nearest with ties going to diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 6cab1e2d242..ae459df8a98 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -4078,7 +4078,7 @@ datetime_from_timestamp(PyObject *cls, TM_FUNC f, PyObject *timestamp, long us; if (_PyTime_ObjectToTimeval(timestamp, - &timet, &us, _PyTime_ROUND_FLOOR) == -1) + &timet, &us, _PyTime_ROUND_HALF_UP) == -1) return NULL; return datetime_from_timet_and_us(cls, f, timet, (int)us, tzinfo);