diff options
Diffstat (limited to 'Lib/datetime.py')
| -rw-r--r-- | Lib/datetime.py | 75 | 
1 files changed, 54 insertions, 21 deletions
diff --git a/Lib/datetime.py b/Lib/datetime.py index 65f95d2030..a15c6b0919 100644 --- a/Lib/datetime.py +++ b/Lib/datetime.py @@ -172,10 +172,6 @@ def _format_time(hh, mm, ss, us):  # Correctly substitute for %z and %Z escapes in strftime formats.  def _wrap_strftime(object, format, timetuple): -    year = timetuple[0] -    if year < 1000: -        raise ValueError("year=%d is before 1000; the datetime strftime() " -                         "methods require year >= 1000" % year)      # Don't call utcoffset() or tzname() unless actually needed.      freplace = None # the string to use for %f      zreplace = None # the string to use for %z @@ -1069,13 +1065,13 @@ class time:      def __eq__(self, other):          if isinstance(other, time): -            return self._cmp(other) == 0 +            return self._cmp(other, allow_mixed=True) == 0          else:              return False      def __ne__(self, other):          if isinstance(other, time): -            return self._cmp(other) != 0 +            return self._cmp(other, allow_mixed=True) != 0          else:              return True @@ -1103,7 +1099,7 @@ class time:          else:              _cmperror(self, other) -    def _cmp(self, other): +    def _cmp(self, other, allow_mixed=False):          assert isinstance(other, time)          mytz = self._tzinfo          ottz = other._tzinfo @@ -1122,7 +1118,10 @@ class time:                         (other._hour, other._minute, other._second,                          other._microsecond))          if myoff is None or otoff is None: -            raise TypeError("cannot compare naive and aware times") +            if allow_mixed: +                return 2 # arbitrary non-zero value +            else: +                raise TypeError("cannot compare naive and aware times")          myhhmm = self._hour * 60 + self._minute - myoff//timedelta(minutes=1)          othhmm = other._hour * 60 + other._minute - otoff//timedelta(minutes=1)          return _cmp((myhhmm, self._second, self._microsecond), @@ -1364,7 +1363,7 @@ class datetime(date):          converter = _time.localtime if tz is None else _time.gmtime          t, frac = divmod(t, 1.0) -        us = round(frac * 1e6) +        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, @@ -1384,7 +1383,7 @@ class datetime(date):      def utcfromtimestamp(cls, t):          "Construct a UTC datetime from a POSIX timestamp (like time.time())."          t, frac = divmod(t, 1.0) -        us = round(frac * 1e6) +        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, @@ -1438,6 +1437,15 @@ class datetime(date):                                    self.hour, self.minute, self.second,                                    dst) +    def timestamp(self): +        "Return POSIX timestamp as float" +        if self._tzinfo is None: +            return _time.mktime((self.year, self.month, self.day, +                                 self.hour, self.minute, self.second, +                                 -1, -1, -1)) + self.microsecond / 1e6 +        else: +            return (self - _EPOCH).total_seconds() +      def utctimetuple(self):          "Return UTC time tuple compatible with time.gmtime()."          offset = self.utcoffset() @@ -1485,8 +1493,32 @@ class datetime(date):          return datetime(year, month, day, hour, minute, second,                            microsecond, tzinfo) -    def astimezone(self, tz): -        if not isinstance(tz, tzinfo): +    def astimezone(self, tz=None): +        if tz is None: +            if self.tzinfo is None: +                raise ValueError("astimezone() requires an aware datetime") +            ts = (self - _EPOCH) // timedelta(seconds=1) +            localtm = _time.localtime(ts) +            local = datetime(*localtm[:6]) +            try: +                # Extract TZ data if available +                gmtoff = localtm.tm_gmtoff +                zone = localtm.tm_zone +            except AttributeError: +                # Compute UTC offset and compare with the value implied +                # by tm_isdst.  If the values match, use the zone name +                # implied by tm_isdst. +                delta = local - datetime(*_time.gmtime(ts)[:6]) +                dst = _time.daylight and localtm.tm_isdst > 0 +                gmtoff = -(_time.altzone if dst else _time.timezone) +                if delta == timedelta(seconds=gmtoff): +                    tz = timezone(delta, _time.tzname[dst]) +                else: +                    tz = timezone(delta) +            else: +                tz = timezone(timedelta(seconds=gmtoff), zone) + +        elif not isinstance(tz, tzinfo):              raise TypeError("tz argument must be an instance of tzinfo")          mytz = self.tzinfo @@ -1610,7 +1642,7 @@ class datetime(date):      def __eq__(self, other):          if isinstance(other, datetime): -            return self._cmp(other) == 0 +            return self._cmp(other, allow_mixed=True) == 0          elif not isinstance(other, date):              return NotImplemented          else: @@ -1618,7 +1650,7 @@ class datetime(date):      def __ne__(self, other):          if isinstance(other, datetime): -            return self._cmp(other) != 0 +            return self._cmp(other, allow_mixed=True) != 0          elif not isinstance(other, date):              return NotImplemented          else: @@ -1656,7 +1688,7 @@ class datetime(date):          else:              _cmperror(self, other) -    def _cmp(self, other): +    def _cmp(self, other, allow_mixed=False):          assert isinstance(other, datetime)          mytz = self._tzinfo          ottz = other._tzinfo @@ -1665,10 +1697,8 @@ class datetime(date):          if mytz is ottz:              base_compare = True          else: -            if mytz is not None: -                myoff = self.utcoffset() -            if ottz is not None: -                otoff = other.utcoffset() +            myoff = self.utcoffset() +            otoff = other.utcoffset()              base_compare = myoff == otoff          if base_compare: @@ -1679,7 +1709,10 @@ class datetime(date):                          other._hour, other._minute, other._second,                          other._microsecond))          if myoff is None or otoff is None: -            raise TypeError("cannot compare naive and aware datetimes") +            if allow_mixed: +                return 2 # arbitrary non-zero value +            else: +                raise TypeError("cannot compare naive and aware datetimes")          # XXX What follows could be done more efficiently...          diff = self - other     # this will take offsets into account          if diff.days < 0: @@ -1893,7 +1926,7 @@ class timezone(tzinfo):  timezone.utc = timezone._create(timedelta(0))  timezone.min = timezone._create(timezone._minoffset)  timezone.max = timezone._create(timezone._maxoffset) - +_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)  """  Some time zone algebra.  For a datetime x, let      x.n = x stripped of its timezone -- its naive time.  | 
