[Python-checkins] r82641 - sandbox/branches/py3k-datetime/datetime.py
alexander.belopolsky
python-checkins at python.org
Thu Jul 8 01:46:38 CEST 2010
Author: alexander.belopolsky
Date: Thu Jul 8 01:46:38 2010
New Revision: 82641
Log:
Issue #5288: Eliminated round-trips between timdelta and int offsets
Modified:
sandbox/branches/py3k-datetime/datetime.py
Modified: sandbox/branches/py3k-datetime/datetime.py
==============================================================================
--- sandbox/branches/py3k-datetime/datetime.py (original)
+++ sandbox/branches/py3k-datetime/datetime.py Thu Jul 8 01:46:38 2010
@@ -176,7 +176,7 @@
if year < 1900:
raise ValueError("year=%d is before 1900; the datetime strftime() "
"methods require year >= 1900" % year)
- # Don't call _utcoffset() or tzname() unless actually needed.
+ # 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
Zreplace = None # the string to use for %Z
@@ -200,14 +200,16 @@
elif ch == 'z':
if zreplace is None:
zreplace = ""
- if hasattr(object, "_utcoffset"):
- offset = object._utcoffset()
+ if hasattr(object, "utcoffset"):
+ offset = object.utcoffset()
if offset is not None:
sign = '+'
- if offset < 0:
+ if offset.days < 0:
offset = -offset
sign = '-'
- h, m = divmod(offset, 60)
+ h, m = divmod(offset, timedelta(hours=1))
+ assert not m % timedelta(0, 60), "whole minute"
+ m //= timedelta(0, 60)
zreplace = '%c%02d%02d' % (sign, h, m)
assert '%' not in zreplace
newformat.append(zreplace)
@@ -250,23 +252,17 @@
def _check_utc_offset(name, offset):
assert name in ("utcoffset", "dst")
if offset is None:
- return None
+ return
if not isinstance(offset, timedelta):
raise TypeError("tzinfo.%s() must return None "
"or timedelta, not '%s'" % (name, type(offset)))
- days = offset.days
- if days < -1 or days > 0:
- offset = 1440 # trigger out-of-range
- else:
- seconds = days * 86400 + offset.seconds
- minutes, seconds = divmod(seconds, 60)
- if seconds or offset.microseconds:
- raise ValueError("tzinfo.%s() must return a whole number "
- "of minutes" % name)
- offset = minutes
- if -1440 < offset < 1440:
- return offset
- raise ValueError("%s()=%d, must be in -1439..1439" % (name, offset))
+ if offset % timedelta(0, 60) or offset.microseconds:
+ raise ValueError("tzinfo.%s() must return a whole number "
+ "of minutes, got %s" % (name, offset))
+ if not -timedelta(1) < offset < timedelta(1):
+ raise ValueError("%s()=%s, must be must be strictly between"
+ " -timedelta(hours=24) and timedelta(hours=24)"
+ % (name, offset))
def _check_date_fields(year, month, day):
if not isinstance(year, int):
@@ -1112,8 +1108,8 @@
if mytz is ottz:
base_compare = True
else:
- myoff = self._utcoffset()
- otoff = other._utcoffset()
+ myoff = self.utcoffset()
+ otoff = other.utcoffset()
base_compare = myoff == otoff
if base_compare:
@@ -1123,17 +1119,20 @@
other._microsecond))
if myoff is None or otoff is None:
raise TypeError("cannot compare naive and aware times")
- myhhmm = self._hour * 60 + self._minute - myoff
- othhmm = other._hour * 60 + other._minute - otoff
+ myhhmm = self._hour * 60 + self._minute - myoff//timedelta(0, 60)
+ othhmm = other._hour * 60 + other._minute - otoff//timedelta(0, 60)
return _cmp((myhhmm, self._second, self._microsecond),
(othhmm, other._second, other._microsecond))
def __hash__(self):
"""Hash."""
- tzoff = self._utcoffset()
+ tzoff = self.utcoffset()
if not tzoff: # zero or None
return hash(self._getstate()[0])
- h, m = divmod(self.hour * 60 + self.minute - tzoff, 60)
+ h, m = divmod(timedelta(hours=self.hour, minutes=self.minute) - tzoff,
+ timedelta(hours=1))
+ assert not m % timedelta(0, 60), "whole minute"
+ m //= timedelta(0, 60)
if 0 <= h < 24:
return hash(time(h, m, self.second, self.microsecond))
return hash((h, m, self.second, self.microsecond))
@@ -1142,14 +1141,16 @@
def _tzstr(self, sep=":"):
"""Return formatted timezone offset (+xx:xx) or None."""
- off = self._utcoffset()
+ off = self.utcoffset()
if off is not None:
- if off < 0:
+ if off.days < 0:
sign = "-"
off = -off
else:
sign = "+"
- hh, mm = divmod(off, 60)
+ hh, mm = divmod(off, timedelta(hours=1))
+ assert not mm % timedelta(0, 60), "whole minute"
+ mm //= timedelta(0, 60)
assert 0 <= hh < 24
off = "%s%02d%s%02d" % (sign, hh, sep, mm)
return off
@@ -1205,16 +1206,10 @@
def utcoffset(self):
"""Return the timezone offset in minutes east of UTC (negative west of
UTC)."""
- offset = _call_tzinfo_method(self._tzinfo, "utcoffset", None)
- offset = _check_utc_offset("utcoffset", offset)
- if offset is not None:
- offset = timedelta(minutes=offset)
- return offset
-
- # Return an integer (or None) instead of a timedelta (or None).
- def _utcoffset(self):
- offset = _call_tzinfo_method(self._tzinfo, "utcoffset", None)
- offset = _check_utc_offset("utcoffset", offset)
+ if self._tzinfo is None:
+ return None
+ offset = self._tzinfo.utcoffset(None)
+ _check_utc_offset("utcoffset", offset)
return offset
def tzname(self):
@@ -1224,7 +1219,9 @@
it mean anything in particular. For example, "GMT", "UTC", "-500",
"-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies.
"""
- name = _call_tzinfo_method(self._tzinfo, "tzname", None)
+ if self._tzinfo is None:
+ return None
+ name = self._tzinfo.tzname(None)
_check_tzname(name)
return name
@@ -1237,10 +1234,10 @@
need to consult dst() unless you're interested in displaying the DST
info.
"""
- offset = _call_tzinfo_method(self._tzinfo, "dst", None)
- offset = _check_utc_offset("dst", offset)
- if offset is not None:
- offset = timedelta(minutes=offset)
+ if self._tzinfo is None:
+ return None
+ offset = self._tzinfo.dst(None)
+ _check_utc_offset("dst", offset)
return offset
def replace(self, hour=None, minute=None, second=None, microsecond=None,
@@ -1263,8 +1260,8 @@
def __bool__(self):
if self.second or self.microsecond:
return True
- offset = self._utcoffset() or 0
- return self.hour * 60 + self.minute - offset != 0
+ offset = self.utcoffset() or timedelta(0)
+ return timedelta(hours=self.hour, minutes=self.minute) != offset
# Pickle support.
@@ -1417,11 +1414,13 @@
def timetuple(self):
"Return local time tuple compatible with time.localtime()."
- dst = self._dst()
+ dst = self.dst()
if dst is None:
dst = -1
elif dst:
dst = 1
+ else:
+ dst = 0
return _build_struct_time(self.year, self.month, self.day,
self.hour, self.minute, self.second,
dst)
@@ -1521,14 +1520,16 @@
sep) +
_format_time(self._hour, self._minute, self._second,
self._microsecond))
- off = self._utcoffset()
+ off = self.utcoffset()
if off is not None:
- if off < 0:
+ if off.days < 0:
sign = "-"
off = -off
else:
sign = "+"
- hh, mm = divmod(off, 60)
+ hh, mm = divmod(off, timedelta(hours=1))
+ assert not mm % timedelta(0, 60), "whole minute"
+ mm //= timedelta(0, 60)
s += "%s%02d:%02d" % (sign, hh, mm)
return s
@@ -1560,16 +1561,10 @@
def utcoffset(self):
"""Return the timezone offset in minutes east of UTC (negative west of
UTC)."""
- offset = _call_tzinfo_method(self._tzinfo, "utcoffset", self)
- offset = _check_utc_offset("utcoffset", offset)
- if offset is not None:
- offset = timedelta(minutes=offset)
- return offset
-
- # Return an integer (or None) instead of a timedelta (or None).
- def _utcoffset(self):
- offset = _call_tzinfo_method(self._tzinfo, "utcoffset", self)
- offset = _check_utc_offset("utcoffset", offset)
+ if self._tzinfo is None:
+ return None
+ offset = self._tzinfo.utcoffset(self)
+ _check_utc_offset("utcoffset", offset)
return offset
def tzname(self):
@@ -1592,16 +1587,10 @@
need to consult dst() unless you're interested in displaying the DST
info.
"""
- offset = _call_tzinfo_method(self._tzinfo, "dst", self)
- offset = _check_utc_offset("dst", offset)
- if offset is not None:
- offset = timedelta(minutes=offset)
- return offset
-
- # Return an integer (or None) instead of a timedelta (or None).1573
- def _dst(self):
- offset = _call_tzinfo_method(self._tzinfo, "dst", self)
- offset = _check_utc_offset("dst", offset)
+ if self._tzinfo is None:
+ return None
+ offset = self._tzinfo.dst(self)
+ _check_utc_offset("dst", offset)
return offset
# Comparisons of datetime objects with other.
@@ -1664,9 +1653,9 @@
base_compare = True
else:
if mytz is not None:
- myoff = self._utcoffset()
+ myoff = self.utcoffset()
if ottz is not None:
- otoff = other._utcoffset()
+ otoff = other.utcoffset()
base_compare = myoff == otoff
if base_compare:
@@ -1721,21 +1710,21 @@
self._microsecond - other._microsecond)
if self._tzinfo is other._tzinfo:
return base
- myoff = self._utcoffset()
- otoff = other._utcoffset()
+ myoff = self.utcoffset()
+ otoff = other.utcoffset()
if myoff == otoff:
return base
if myoff is None or otoff is None:
raise TypeError("cannot mix naive and timezone-aware time")
- return base + timedelta(minutes = otoff-myoff)
+ return base + otoff - myoff
def __hash__(self):
- tzoff = self._utcoffset()
+ tzoff = self.utcoffset()
if tzoff is None:
return hash(self._getstate()[0])
days = _ymd2ord(self.year, self.month, self.day)
- seconds = self.hour * 3600 + (self.minute - tzoff) * 60 + self.second
- return hash(timedelta(days, seconds, self.microsecond))
+ seconds = self.hour * 3600 + self.minute * 60 + self.second
+ return hash(timedelta(days, seconds, self.microsecond) - tzoff)
# Pickle support.
More information about the Python-checkins
mailing list