Author: Brian Kearns <[email protected]>
Branch:
Changeset: r80916:3944e79025c8
Date: 2015-11-24 16:36 -0500
http://bitbucket.org/pypy/pypy/changeset/3944e79025c8/
Log: more optimizations for timedelta
diff --git a/lib_pypy/datetime.py b/lib_pypy/datetime.py
--- a/lib_pypy/datetime.py
+++ b/lib_pypy/datetime.py
@@ -447,6 +447,12 @@
raise TypeError("unsupported type for timedelta %s component: %s" %
(tag, type(num)))
+def _normalize_pair(hi, lo, factor):
+ if lo < 0 or lo >= factor:
+ inc, lo = divmod(lo, factor)
+ hi += inc
+ return hi, lo
+
class timedelta(object):
"""Represent the difference between two datetime objects.
@@ -492,6 +498,13 @@
def _from_microseconds(cls, us):
s, us = divmod(us, _US_PER_SECOND)
d, s = divmod(s, _SECONDS_PER_DAY)
+ return cls._create(d, s, us, False)
+
+ @classmethod
+ def _create(cls, d, s, us, normalize):
+ if normalize:
+ s, us = _normalize_pair(s, us, 1000000)
+ d, s = _normalize_pair(d, s, 24*3600)
if not -_MAX_DELTA_DAYS <= d <= _MAX_DELTA_DAYS:
raise OverflowError("days=%d; must have magnitude <= %d" % (d,
_MAX_DELTA_DAYS))
@@ -556,9 +569,10 @@
if isinstance(other, timedelta):
# for CPython compatibility, we cannot use
# our __class__ here, but need a real timedelta
- return timedelta(self._days + other._days,
- self._seconds + other._seconds,
- self._microseconds + other._microseconds)
+ return timedelta._create(self._days + other._days,
+ self._seconds + other._seconds,
+ self._microseconds + other._microseconds,
+ True)
return NotImplemented
__radd__ = __add__
@@ -567,9 +581,10 @@
if isinstance(other, timedelta):
# for CPython compatibility, we cannot use
# our __class__ here, but need a real timedelta
- return timedelta(self._days - other._days,
- self._seconds - other._seconds,
- self._microseconds - other._microseconds)
+ return timedelta._create(self._days - other._days,
+ self._seconds - other._seconds,
+ self._microseconds - other._microseconds,
+ True)
return NotImplemented
def __rsub__(self, other):
@@ -580,12 +595,18 @@
def __neg__(self):
# for CPython compatibility, we cannot use
# our __class__ here, but need a real timedelta
- return timedelta(-self._days,
- -self._seconds,
- -self._microseconds)
+ return timedelta._create(-self._days,
+ -self._seconds,
+ -self._microseconds,
+ True)
def __pos__(self):
- return self
+ # for CPython compatibility, we cannot use
+ # our __class__ here, but need a real timedelta
+ return timedelta._create(self._days,
+ self._seconds,
+ self._microseconds,
+ False)
def __abs__(self):
if self._days < 0:
@@ -932,11 +953,11 @@
def __sub__(self, other):
"""Subtract two dates, or a date and a timedelta."""
if isinstance(other, timedelta):
- return self + timedelta(-other.days)
+ return self + timedelta._create(-other.days, 0, 0, False)
if isinstance(other, date):
days1 = self.toordinal()
days2 = other.toordinal()
- return timedelta(days1 - days2)
+ return timedelta._create(days1 - days2, 0, 0, False)
return NotImplemented
def weekday(self):
@@ -1303,7 +1324,7 @@
offset = self._tzinfo.utcoffset(None)
offset = _check_utc_offset("utcoffset", offset)
if offset is not None:
- offset = timedelta(minutes=offset)
+ offset = timedelta._create(0, offset * 60, 0, True)
return offset
# Return an integer (or None) instead of a timedelta (or None).
@@ -1341,7 +1362,7 @@
offset = self._tzinfo.dst(None)
offset = _check_utc_offset("dst", offset)
if offset is not None:
- offset = timedelta(minutes=offset)
+ offset = timedelta._create(0, offset * 60, 0, True)
return offset
# Return an integer (or None) instead of a timedelta (or None).
@@ -1674,7 +1695,7 @@
offset = self._tzinfo.utcoffset(self)
offset = _check_utc_offset("utcoffset", offset)
if offset is not None:
- offset = timedelta(minutes=offset)
+ offset = timedelta._create(0, offset * 60, 0, True)
return offset
# Return an integer (or None) instead of a timedelta (or None).
@@ -1712,7 +1733,7 @@
offset = self._tzinfo.dst(self)
offset = _check_utc_offset("dst", offset)
if offset is not None:
- offset = timedelta(minutes=offset)
+ offset = timedelta._create(0, offset * 60, 0, True)
return offset
# Return an integer (or None) instead of a timedelta (or None).
@@ -1829,13 +1850,12 @@
return self + -other
return NotImplemented
- days1 = self.toordinal()
- days2 = other.toordinal()
- secs1 = self._second + self._minute * 60 + self._hour * 3600
- secs2 = other._second + other._minute * 60 + other._hour * 3600
- base = timedelta(days1 - days2,
- secs1 - secs2,
- self._microsecond - other._microsecond)
+ delta_d = self.toordinal() - other.toordinal()
+ delta_s = (self._hour - other._hour) * 3600 + \
+ (self._minute - other._minute) * 60 + \
+ (self._second - other._second)
+ delta_us = self._microsecond - other._microsecond
+ base = timedelta._create(delta_d, delta_s, delta_us, True)
if self._tzinfo is other._tzinfo:
return base
myoff = self._utcoffset()
diff --git a/pypy/module/test_lib_pypy/test_datetime.py
b/pypy/module/test_lib_pypy/test_datetime.py
--- a/pypy/module/test_lib_pypy/test_datetime.py
+++ b/pypy/module/test_lib_pypy/test_datetime.py
@@ -312,6 +312,8 @@
def test_return_types(self):
td = datetime.timedelta(5)
assert type(td.total_seconds()) is float
+ class sub(datetime.timedelta): pass
+ assert type(+sub()) is datetime.timedelta
class TestDatetimeHost(BaseTestDatetime):
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit