Index: datetime.py =================================================================== --- datetime.py (revision 82082) +++ datetime.py (working copy) @@ -19,6 +19,9 @@ import time as _time import math as _math +def cmp(x, y): + return 0 if x == y else 1 if x > y else -1 + MINYEAR = 1 MAXYEAR = 9999 @@ -467,21 +470,21 @@ daysecondsfrac, daysecondswhole = _math.modf(dayfrac * (24.*3600.)) assert daysecondswhole == int(daysecondswhole) # can't overflow s = int(daysecondswhole) - assert days == long(days) - d = long(days) + assert days == int(days) + d = int(days) else: daysecondsfrac = 0.0 d = days assert isinstance(daysecondsfrac, float) assert abs(daysecondsfrac) <= 1.0 - assert isinstance(d, (int, long)) + assert isinstance(d, int) assert abs(s) <= 24 * 3600 # days isn't referenced again before redefinition if isinstance(seconds, float): secondsfrac, seconds = _math.modf(seconds) - assert seconds == long(seconds) - seconds = long(seconds) + assert seconds == int(seconds) + seconds = int(seconds) secondsfrac += daysecondsfrac assert abs(secondsfrac) <= 2.0 else: @@ -490,7 +493,7 @@ assert isinstance(secondsfrac, float) assert abs(secondsfrac) <= 2.0 - assert isinstance(seconds, (int, long)) + assert isinstance(seconds, int) days, seconds = divmod(seconds, 24*3600) d += days s += int(seconds) # can't overflow @@ -504,14 +507,14 @@ if isinstance(microseconds, float): microseconds += usdouble - microseconds = round(microseconds) + microseconds = round(microseconds, 0) seconds, microseconds = divmod(microseconds, 1e6) assert microseconds == int(microseconds) - assert seconds == long(seconds) + assert seconds == int(seconds) days, seconds = divmod(seconds, 24.*3600.) - assert days == long(days) + assert days == int(days) assert seconds == int(seconds) - d += long(days) + d += int(days) s += int(seconds) # can't overflow assert isinstance(s, int) assert abs(s) <= 3 * 24 * 3600 @@ -524,7 +527,7 @@ assert abs(s) <= 3 * 24 * 3600 microseconds = float(microseconds) microseconds += usdouble - microseconds = round(microseconds) + microseconds = round(microseconds, 0) assert abs(s) <= 3 * 24 * 3600 assert abs(microseconds) < 3.1e6 @@ -538,7 +541,7 @@ days, s = divmod(s, 24*3600) d += days - assert isinstance(d, (int, long)) + assert isinstance(d, int) assert isinstance(s, int) and 0 <= s < 24*3600 assert isinstance(us, int) and 0 <= us < 1000000 @@ -622,25 +625,57 @@ return self def __mul__(self, other): - if isinstance(other, (int, long)): + if isinstance(other, int): # for CPython compatibility, we cannot use # our __class__ here, but need a real timedelta return timedelta(self.__days * other, self.__seconds * other, self.__microseconds * other) + if isinstance(other, float): + a, b = other.as_integer_ratio() + return self * a / b return NotImplemented __rmul__ = __mul__ - def __div__(self, other): - if isinstance(other, (int, long)): - usec = ((self.__days * (24*3600L) + self.__seconds) * 1000000 + - self.__microseconds) + def _to_microseconds(self): + return ((self.__days * (24*3600) + self.__seconds) * 1000000 + + self.__microseconds) + + def __floordiv__(self, other): + if not isinstance(other, (int, timedelta)): + return NotImplemented + usec = self._to_microseconds() + if isinstance(other, timedelta): + return usec // other._to_microseconds() + if isinstance(other, int): return timedelta(0, 0, usec // other) + + def __truediv__(self, other): + if not isinstance(other, (int, float, timedelta)): + return NotImplemented + usec = self._to_microseconds() + if isinstance(other, timedelta): + return usec / other._to_microseconds() + if isinstance(other, int): + return timedelta(0, 0, usec / other) + if isinstance(other, float): + a, b = other.as_integer_ratio() + return timedelta(0, 0, b * usec / a) + + def __mod__(self, other): + if isinstance(other, timedelta): + r = self._to_microseconds() % other._to_microseconds() + return timedelta(0, 0, r) return NotImplemented - __floordiv__ = __div__ - + def __divmod__(self, other): + if isinstance(other, timedelta): + q, r = divmod(self._to_microseconds(), + other._to_microseconds()) + return q, timedelta(0, 0, r) + return NotImplemented + # Comparisons. def __eq__(self, other): @@ -686,7 +721,7 @@ def __hash__(self): return hash(self.__getstate()) - def __nonzero__(self): + def __bool__(self): return (self.__days != 0 or self.__seconds != 0 or self.__microseconds != 0) @@ -706,7 +741,7 @@ microseconds=999999) timedelta.resolution = timedelta(microseconds=1) -class date(object): +class date: """Concrete date type. Constructors: @@ -742,7 +777,7 @@ year, month, day (required, base 1) """ - if isinstance(year, str): + if isinstance(year, bytes): # Pickle support self = object.__new__(cls) self.__setstate(year) @@ -878,26 +913,17 @@ def __lt__(self, other): if isinstance(other, date): return self.__cmp(other) < 0 - elif hasattr(other, "timetuple"): - return NotImplemented - else: - _cmperror(self, other) + return NotImplemented def __ge__(self, other): if isinstance(other, date): return self.__cmp(other) >= 0 - elif hasattr(other, "timetuple"): - return NotImplemented - else: - _cmperror(self, other) + return NotImplemented def __gt__(self, other): if isinstance(other, date): return self.__cmp(other) > 0 - elif hasattr(other, "timetuple"): - return NotImplemented - else: - _cmperror(self, other) + return NotImplemented def __cmp(self, other): assert isinstance(other, date) @@ -984,12 +1010,12 @@ def __getstate(self): yhi, ylo = divmod(self.__year, 256) - return ("%c%c%c%c" % (yhi, ylo, self.__month, self.__day), ) + return bytes([yhi, ylo, self.__month, self.__day]), def __setstate(self, string): - if len(string) != 4 or not (1 <= ord(string[2]) <= 12): + if len(string) != 4 or not (1 <= string[2] <= 12): raise TypeError("not enough arguments") - yhi, ylo, self.__month, self.__day = map(ord, string) + yhi, ylo, self.__month, self.__day = string self.__year = yhi * 256 + ylo def __reduce__(self): @@ -1063,7 +1089,7 @@ args = getinitargs() else: args = () - getstate = getattr(self, "__getstate__", None) + getstate = getattr(self, "__getstate", None) if getstate: state = getstate() else: @@ -1334,9 +1360,9 @@ offset = _check_utc_offset("dst", offset) return offset - def __nonzero__(self): + def __bool__(self): if self.second or self.microsecond: - return 1 + return True offset = self._utcoffset() or 0 return self.hour * 60 + self.minute - offset != 0 @@ -1378,7 +1404,7 @@ def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0, microsecond=0, tzinfo=None): - if isinstance(year, str): + if isinstance(year, bytes): # Pickle support self = date.__new__(cls, year[:4]) self.__setstate(year, month) @@ -1543,7 +1569,7 @@ # Convert self to UTC, and attach the new time zone object. myoffset = self.utcoffset() if myoffset is None: - raise ValuError("astimezone() requires an aware datetime") + raise ValueError("astimezone() requires an aware datetime") utc = (self - myoffset).replace(tzinfo=tz) # Convert from UTC to tz's local time. @@ -1607,8 +1633,7 @@ def strptime(cls, date_string, format): 'string, format -> new datetime parsed from a string (like time.strptime()).' import _strptime - tt, us = _strptime._strptime(date_string, format) - return cls(*(tt[0:6] + (us,))) + return _strptime._strptime_datetime(cls, date_string, format) def utcoffset(self): """Return the timezone offset in minutes east of UTC (negative west of @@ -1662,7 +1687,7 @@ def __eq__(self, other): if isinstance(other, datetime): return self.__cmp(other) == 0 - elif hasattr(other, "timetuple") and not isinstance(other, date): + elif not isinstance(other, date): return NotImplemented else: return False @@ -1670,7 +1695,7 @@ def __ne__(self, other): if isinstance(other, datetime): return self.__cmp(other) != 0 - elif hasattr(other, "timetuple") and not isinstance(other, date): + elif not isinstance(other, date): return NotImplemented else: return True @@ -1678,7 +1703,7 @@ def __le__(self, other): if isinstance(other, datetime): return self.__cmp(other) <= 0 - elif hasattr(other, "timetuple") and not isinstance(other, date): + elif not isinstance(other, date): return NotImplemented else: _cmperror(self, other) @@ -1686,7 +1711,7 @@ def __lt__(self, other): if isinstance(other, datetime): return self.__cmp(other) < 0 - elif hasattr(other, "timetuple") and not isinstance(other, date): + elif not isinstance(other, date): return NotImplemented else: _cmperror(self, other) @@ -1694,7 +1719,7 @@ def __ge__(self, other): if isinstance(other, datetime): return self.__cmp(other) >= 0 - elif hasattr(other, "timetuple") and not isinstance(other, date): + elif not isinstance(other, date): return NotImplemented else: _cmperror(self, other) @@ -1702,7 +1727,7 @@ def __gt__(self, other): if isinstance(other, datetime): return self.__cmp(other) > 0 - elif hasattr(other, "timetuple") and not isinstance(other, date): + elif not isinstance(other, date): return NotImplemented else: _cmperror(self, other) @@ -1778,7 +1803,7 @@ if myoff == otoff: return base if myoff is None or otoff is None: - raise TypeError, "cannot mix naive and timezone-aware time" + raise TypeError("cannot mix naive and timezone-aware time") return base + timedelta(minutes = otoff-myoff) def __hash__(self): @@ -1797,9 +1822,9 @@ yhi, ylo = divmod(self.__year, 256) us2, us3 = divmod(self.__microsecond, 256) us1, us2 = divmod(us2, 256) - basestate = ("%c" * 10) % (yhi, ylo, self.__month, self.__day, - self.__hour, self.__minute, self.__second, - us1, us2, us3) + basestate = bytes([yhi, ylo, self.__month, self.__day, + self.__hour, self.__minute, self.__second, + us1, us2, us3]) if self._tzinfo is None: return (basestate,) else: @@ -1807,7 +1832,7 @@ def __setstate(self, string, tzinfo): (yhi, ylo, self.__month, self.__day, self.__hour, - self.__minute, self.__second, us1, us2, us3) = map(ord, string) + self.__minute, self.__second, us1, us2, us3) = string self.__year = yhi * 256 + ylo self.__microsecond = (((us1 << 8) | us2) << 8) | us3 self._tzinfo = tzinfo @@ -1832,6 +1857,89 @@ week1monday += 7 return week1monday +class timezone(tzinfo): + def __init__(self, offset, *args): + # Reproduce C behavior + n = len(args) + if n > 1: + raise TypeError("timezone() takes at most 2 arguments (%d given)" + % n) + if n == 0: + name = None + else: + name = args[0] + if not isinstance(name, str): + raise TypeError("name must be a string") + if isinstance(offset, timedelta): + if self._minoffset <= offset <= self._maxoffset: + if (offset.microseconds != 0 or + offset.seconds % 60 != 0): + raise ValueError("offset must be whole" + " number of minutes") + self.__offset = offset + else: + raise ValueError("offset out of range") + else: + raise TypeError("offset must be timedelta") + + self.__name = name + + def __eq__(self, other): + return self.__offset == other.__offset + + def __hash__(self): + return hash(self.__offset) + + def __str__(self): + return self.tzname(None) + + def utcoffset(self, dt): + if isinstance(dt, datetime) or dt is None: + return self.__offset + raise TypeError("utcoffset() argument must be a datetime instance" + " or None") + + def tzname(self, dt): + if isinstance(dt, datetime) or dt is None: + if self.__name is None: + return self._name_from_offset(self.__offset) + return self.__name + raise TypeError("tzname() argument must be a datetime instance" + " or None") + + def dst(self, dt): + if isinstance(dt, datetime) or dt is None: + return None + raise TypeError("dst() argument must be a datetime instance" + " or None") + + def fromutc(self, dt): + if isinstance(dt, datetime): + if dt.tzinfo is not self: + raise ValueError("fromutc: dt.tzinfo " + "is not self") + return dt + self.__offset + raise TypeError("fromutc() argument must be a datetime instance" + " or None") + + _maxoffset = timedelta(hours=23, minutes=59) + _minoffset = -_maxoffset + + @staticmethod + def _name_from_offset(delta): + if delta < timedelta(0): + sign = '-' + delta = -delta + else: + sign = '+' + hours, rest = divmod(delta, timedelta(hours=1)) + minutes = rest // timedelta(minutes=1) + return 'UTC{}{:02d}:{:02d}'.format(sign, hours, minutes) + +timezone.utc = timezone(timedelta(0)) +timezone.min = timezone(timezone._minoffset) +timezone.max = timezone(timezone._maxoffset) + """ Some time zone algebra. For a datetime x, let x.n = x stripped of its timezone -- its naive time.