Author: Brian Kearns <bdkea...@gmail.com>
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
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to