[Python-checkins] CVS: python/nondist/sandbox/datetime datetime.py,1.27,1.28 test_datetime.py,1.19,1.20
Guido van Rossum
gvanrossum@users.sourceforge.net
Sun, 03 Mar 2002 15:16:23 -0800
Update of /cvsroot/python/python/nondist/sandbox/datetime
In directory usw-pr-cvs1:/tmp/cvs-serv22462
Modified Files:
datetime.py test_datetime.py
Log Message:
Attempt to fix ctime() to avoid dependence on time.localtime().
XXX This probably breaks when the time module's epoch isn't 1/1/1970!
- Add global arrays _MONTHNAMES and _DAYNAMES
- Augment class tmxxx:
- Note in time() docstring that it assumes UTC
- Add ctime() method
- Add _localtzoffset() function which attempts to calculate the
tzoffset for a given local time. It asks localtime() if possible,
but if that fails just assumes time.timezone.
- Use _localtzoffset() to calculate the default tzoffset; correct, but
even slower than before
- Change _mktime() to use tmxxx() instead of the time module
- Change _utc_ymdHM() to use tmxxx() instead of repeating the work
- Change ctime() and utcctime() to do the right thing, using tmxxx
(mostly; there's some stuff with renormalizing for the local time
zone that I've probably gotten wrong)
- Fix a comment or two
Index: datetime.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/datetime.py,v
retrieving revision 1.27
retrieving revision 1.28
diff -C2 -d -r1.27 -r1.28
*** datetime.py 3 Mar 2002 21:24:33 -0000 1.27
--- datetime.py 3 Mar 2002 23:16:21 -0000 1.28
***************
*** 92,95 ****
--- 92,100 ----
return year, month, n-dbm
+ # Month and day names. For localized versions, see the calendar module.
+ _MONTHNAMES = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
+ _DAYNAMES = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
+
# This is a start at a struct tm workalike. Goals:
#
***************
*** 141,145 ****
def time(self):
! "Return Unixish timestamp, as a float."
if self.ordinal is None:
self.ordinal = _ymd2ord(self.year, self.month, self.day)
--- 146,150 ----
def time(self):
! "Return Unixish timestamp, as a float (assuming UTC)."
if self.ordinal is None:
self.ordinal = _ymd2ord(self.year, self.month, self.day)
***************
*** 148,151 ****
--- 153,183 ----
return seconds + self.second + self.microsecond / 1e6
+ def ctime(self):
+ "Return ctime() style string."
+ if self.ordinal is None:
+ self.ordinal = _ymd2ord(self.year, self.month, self.day)
+ weekday = self.ordinal % 7 or 7
+ return "%s %s %2d %02d:%02d:%02d %04d" % (
+ _DAYNAMES[weekday - 1],
+ _MONTHNAMES[self.month - 1],
+ self.day,
+ self.hour, self.minute, self.second,
+ self.year)
+
+
+ def _localtzoffset(year, month, day, hour, minute):
+ "Return tzoffset for local time corresponding to given date/time."
+ try:
+ t = _time.mktime((year, month, day, hour, minute, 0, -1, -1, -1))
+ tm = _time.localtime(t)
+ if tm.tm_isdst > 0:
+ return - (_time.altzone // 60)
+ else:
+ return - (_time.timezone // 60)
+ except (ValueError, OverflowError):
+ # XXX Dates out of range for mktime() never see DST
+ return - (_time.timezone // 60)
+
+
class basetime(object):
"""Abstract date/time type.
***************
*** 331,336 ****
"""
- __isdst = None
-
def __init__(self, year, month, day, hour=0, minute=0, second=0,
microsecond=0, tzoffset=None):
--- 363,366 ----
***************
*** 361,372 ****
raise ValueError('microsecond must be in 0..999999', microsecond)
if tzoffset is None:
! # XXX This decides whether local time is DST or not once,
! # and never changes its mind, regardless how long we run
! if datetime.__isdst is None:
! datetime.__isdst = _time.localtime()[-1]
! if datetime.__isdst > 0:
! tzoffset = -(_time.altzone // 60)
! else:
! tzoffset = -(_time.timezone // 60)
if not -1439 <= tzoffset <= 1439:
raise ValueError('tzoffset must be in -1439..1439', tzoffset)
--- 391,396 ----
raise ValueError('microsecond must be in 0..999999', microsecond)
if tzoffset is None:
! # XXX Correct, but expensive
! tzoffset = _localtzoffset(year, month, day, hour, minute)
if not -1439 <= tzoffset <= 1439:
raise ValueError('tzoffset must be in -1439..1439', tzoffset)
***************
*** 457,467 ****
# Standard conversions, __cmp__, __hash__ (and helpers)
def _mktime(self):
! # Helper to call time.mktime()
! y, m, d = self.__year, self.__month, self.__day
! hh, mm, ss = self.__hour, self.__minute, self.__second
! mm -= self.__tzoffset # tzoffset is negative in the US
! ss -= _time.timezone # but time.timezone has the opposite sign!
! return _time.mktime((y, m, d, hh, mm, ss, -1, -1, -1))
def _timestamp(self):
--- 481,491 ----
# Standard conversions, __cmp__, __hash__ (and helpers)
+ # XXX These should be done without reference to the time module
+
def _mktime(self):
! # Helper to return a POSIX-ish timestamp
! t = tmxxx(self.__year, self.__month, self.__day,
! self.__hour, self.__minute - self.__tzoffset, self.__second)
! return t.time() + self.__microsecond / 1e6
def _timestamp(self):
***************
*** 505,539 ****
def _utc_ymdHM(self):
# Helper to return (year, month, day, hour, minute) in UTC equivalent
! y, m, d = self.__year, self.__month, self.__day
! H, M = self.__hour, self.__minute
! if self.__tzoffset:
! M -= self.__tzoffset
! if not 0 <= M <= 59:
! carry, M = divmod(M, 60)
! H += carry
! if not 0 <= H <= 23:
! carry, H = divmod(H, 24)
! # tzoffset is less than a day, so carry is no more than 1.
! if carry > 0:
! assert carry == 1
! d += 1
! if d > _days_in_month(m, y):
! d = 1
! m += 1
! if m > 12:
! m = 1
! y += 1
! else:
! assert carry == -1
! d -= 1
! if d == 0:
! m -= 1
! if m > 0:
! d = _days_in_month(m, y)
! else:
! d = 31
! m = 12
! y -= 1
! return y, m, d, H, M
def __hash__(self):
--- 529,535 ----
def _utc_ymdHM(self):
# Helper to return (year, month, day, hour, minute) in UTC equivalent
! t = tmxxx(self.__year, self.__month, self.__day,
! self.__hour, self.__minute - self.__tzoffset)
! return t.year, t.month, t.day, t.hour, t.minute
def __hash__(self):
***************
*** 559,563 ****
def ctime(self):
"Format a la ctime() in local time."
! return _time.strftime("%c", _time.localtime(self._mktime()))
def strftime(self, fmt):
--- 555,568 ----
def ctime(self):
"Format a la ctime() in local time."
! tzoffset = _localtzoffset(self.__year, self.__month, self.__day, 0, 0)
! t = tmxxx(self.__year, self.__month, self.__day, self.__hour,
! self.__minute - self.__tzoffset + tzoffset, self.__second)
! tzoffset1 = _localtzoffset(t.year, t.month, t.day, t.hour, t.minute)
! if tzoffset1 != tzoffset:
! t = tmxxx(t.year, t.month, t.day, t.hour,
! t.minute - tzoffset + tzoffset1, self.__second)
! tzoffset2 = _localtzoffset(t.year, t.month, t.day, t.hour, t.minute)
! assert tzoffset2 == tzoffset1 # XXX Hah!
! return t.ctime()
def strftime(self, fmt):
***************
*** 567,571 ****
def utcctime(self):
"Format a la ctime() in UTC."
! return _time.strftime("%c", _time.gmtime(self._mktime()))
def utcstrftime(self, fmt):
--- 572,578 ----
def utcctime(self):
"Format a la ctime() in UTC."
! t = tmxxx(self.__year, self.__month, self.__day,
! self.__hour, self.__minute - self.__tzoffset, self.__second)
! return t.ctime()
def utcstrftime(self, fmt):
***************
*** 652,656 ****
week1monday = _isoweek1monday(year)
today = _ymd2ord(self.__year, self.__month, self.__day)
! # Internally, week has origin 0
week, day = divmod(today - week1monday, 7)
if week < 0:
--- 659,663 ----
week1monday = _isoweek1monday(year)
today = _ymd2ord(self.__year, self.__month, self.__day)
! # Internally, week and day have origin 0
week, day = divmod(today - week1monday, 7)
if week < 0:
Index: test_datetime.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/test_datetime.py,v
retrieving revision 1.19
retrieving revision 1.20
diff -C2 -d -r1.19 -r1.20
*** test_datetime.py 3 Mar 2002 21:24:33 -0000 1.19
--- test_datetime.py 3 Mar 2002 23:16:21 -0000 1.20
***************
*** 316,319 ****
--- 316,334 ----
self.assertEqual(timestamp, tm.time())
+ def test_ctime(self):
+ t = datetime(2002, 3, 2, 18, 3, 5, 123)
+ self.assertEqual(t.ctime(), "Sat Mar 2 18:03:05 2002")
+ # XXX Can only test utcctime() in known timezone :-(
+ # XXX What about the southern hemisphere, where this is DST?
+ import time
+ if time.timezone == 5*3600:
+ self.assertEqual(t.utcctime(), "Sat Mar 2 23:03:05 2002")
+ elif time.timezone == 0:
+ self.assertEqual(t.utcctime(), "Sat Mar 2 18:03:05 2002")
+ elif time.timezone == 3600:
+ self.assertEqual(t.utcctime(), "Sat Mar 2 17:03:05 2002")
+ else:
+ self.fail("Can't test utcctime()")
+
def test_suite():
s1 = unittest.makeSuite(TestDateTime, 'test')