diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2015-09-04 21:57:25 (GMT) |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2015-09-04 21:57:25 (GMT) |
commit | adfefa527a32e711c1bea9c1ac32c20e9cce0660 (patch) | |
tree | 8e03b6d95d1f6f32780d8535aa5b60d411d0646f /Lib/datetime.py | |
parent | 19bbb9af678040e8963edfcfdc30e9f87b106fb9 (diff) | |
download | cpython-adfefa527a32e711c1bea9c1ac32c20e9cce0660.zip cpython-adfefa527a32e711c1bea9c1ac32c20e9cce0660.tar.gz cpython-adfefa527a32e711c1bea9c1ac32c20e9cce0660.tar.bz2 |
Issue #23517: Fix implementation of the ROUND_HALF_UP rounding mode in
datetime.datetime.fromtimestamp() and datetime.datetime.utcfromtimestamp().
microseconds sign should be kept before rounding.
Diffstat (limited to 'Lib/datetime.py')
-rw-r--r-- | Lib/datetime.py | 48 |
1 files changed, 21 insertions, 27 deletions
diff --git a/Lib/datetime.py b/Lib/datetime.py index 5ba2ddb..3bf9edc 100644 --- a/Lib/datetime.py +++ b/Lib/datetime.py @@ -1374,28 +1374,34 @@ class datetime(date): return self._tzinfo @classmethod - def fromtimestamp(cls, t, tz=None): + def _fromtimestamp(cls, t, utc, tz): """Construct a datetime from a POSIX timestamp (like time.time()). A timezone info object may be passed in as well. """ - _check_tzinfo_arg(tz) - - converter = _time.localtime if tz is None else _time.gmtime - - t, frac = divmod(t, 1.0) + frac, t = _math.modf(t) 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, - # roll over to seconds, otherwise, ValueError is raised - # by the constructor. - if us == 1000000: + if us >= 1000000: t += 1 - us = 0 + us -= 1000000 + elif us < 0: + t -= 1 + us += 1000000 + + converter = _time.gmtime if utc else _time.localtime y, m, d, hh, mm, ss, weekday, jday, dst = converter(t) ss = min(ss, 59) # clamp out leap seconds if the platform has them - result = cls(y, m, d, hh, mm, ss, us, tz) + return cls(y, m, d, hh, mm, ss, us, tz) + + @classmethod + def fromtimestamp(cls, t, tz=None): + """Construct a datetime from a POSIX timestamp (like time.time()). + + A timezone info object may be passed in as well. + """ + _check_tzinfo_arg(tz) + + result = cls._fromtimestamp(t, tz is not None, tz) if tz is not None: result = tz.fromutc(result) return result @@ -1403,19 +1409,7 @@ class datetime(date): @classmethod def utcfromtimestamp(cls, t): """Construct a naive UTC datetime from a POSIX timestamp.""" - t, frac = divmod(t, 1.0) - 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, - # roll over to seconds, otherwise, ValueError is raised - # by the constructor. - if us == 1000000: - t += 1 - us = 0 - y, m, d, hh, mm, ss, weekday, jday, dst = _time.gmtime(t) - ss = min(ss, 59) # clamp out leap seconds if the platform has them - return cls(y, m, d, hh, mm, ss, us) + return cls._fromtimestamp(t, True, None) @classmethod def now(cls, tz=None): |