summaryrefslogtreecommitdiff
path: root/Lib/datetime.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/datetime.py')
-rw-r--r--Lib/datetime.py64
1 files changed, 34 insertions, 30 deletions
diff --git a/Lib/datetime.py b/Lib/datetime.py
index db13b12ef3..6b2ac33a32 100644
--- a/Lib/datetime.py
+++ b/Lib/datetime.py
@@ -316,6 +316,14 @@ def _divide_and_round(a, b):
return q
+def _round_half_up(x):
+ """Round to nearest with ties going away from zero."""
+ if x >= 0.0:
+ return _math.floor(x + 0.5)
+ else:
+ return _math.ceil(x - 0.5)
+
+
class timedelta:
"""Represent the difference between two datetime objects.
@@ -399,7 +407,7 @@ class timedelta:
# secondsfrac isn't referenced again
if isinstance(microseconds, float):
- microseconds = round(microseconds + usdouble)
+ microseconds = _round_half_up(microseconds + usdouble)
seconds, microseconds = divmod(microseconds, 1000000)
days, seconds = divmod(seconds, 24*3600)
d += days
@@ -410,7 +418,7 @@ class timedelta:
days, seconds = divmod(seconds, 24*3600)
d += days
s += seconds
- microseconds = round(microseconds + usdouble)
+ microseconds = _round_half_up(microseconds + usdouble)
assert isinstance(s, int)
assert isinstance(microseconds, int)
assert abs(s) <= 3 * 24 * 3600
@@ -1366,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)
- us = int(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:
+ frac, t = _math.modf(t)
+ us = _round_half_up(frac * 1e6)
+ 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
@@ -1395,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 = int(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):
@@ -1918,6 +1920,8 @@ class timezone(tzinfo):
@staticmethod
def _name_from_offset(delta):
+ if not delta:
+ return 'UTC'
if delta < timedelta(0):
sign = '-'
delta = -delta