[Python-checkins] CVS: python/nondist/sandbox/datetime datetime.py,1.53,1.54 test_datetime.py,1.37,1.38

Guido van Rossum gvanrossum@users.sourceforge.net
Tue, 05 Mar 2002 17:25:18 -0800


Update of /cvsroot/python/python/nondist/sandbox/datetime
In directory usw-pr-cvs1:/tmp/cvs-serv5073

Modified Files:
	datetime.py test_datetime.py 
Log Message:
Eradicate all references to time zone offset.
This implements naive time'' as I described on python-dev.
Some cleanup remains to be done...

Index: datetime.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/datetime.py,v
retrieving revision 1.53
retrieving revision 1.54
diff -C2 -d -r1.53 -r1.54
*** datetime.py	5 Mar 2002 19:11:43 -0000	1.53
--- datetime.py	6 Mar 2002 01:25:13 -0000	1.54
***************
*** 249,267 ****
  
  
- 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):
-         # Dates out of range for mktime() never see DST.
-         # As a reasonable guess, though, we can try a year in mktime()'s range
-         # with the same leap-year-ness as the given year.
-         return _localtzoffset(2003 + _is_leap(year), month, day, hour, minute)
- 
  class basetime(object):
      """Abstract date/time type.
--- 249,252 ----
***************
*** 423,443 ****
  
      def __str__(self):
!         def plural(n):
!             return n, n != 1 and "s" or ""
!         L = []
          if self.__days:
!             L.append("%d day%s" % plural(self.__days))
!         if self.__seconds:
!             mm, ss = divmod(self.__seconds, 60)
!             hh, mm = divmod(mm, 60)
!             if hh:
!                 L.append("%d hour%s" % plural(hh))
!             if mm:
!                 L.append("%d minute%s" % plural(mm))
!             if ss:
!                 L.append("%d second%s" % plural(ss))
          if self.__microseconds:
!             L.append("%d microsecond%s" % plural(self.__microseconds))
!         return ", ".join(L)
  
      days = property(lambda self: self.__days, doc="days")
--- 408,421 ----
  
      def __str__(self):
!         mm, ss = divmod(self.__seconds, 60)
!         hh, mm = divmod(mm, 60)
!         s = "%d:%02d:%02d" % (hh, mm, ss)
          if self.__days:
!             def plural(n):
!                 return n, n != 1 and "s" or ""
!             s = ("%d day%s, " % plural(self.__days)) + s
          if self.__microseconds:
!             s = s + ".%06d" % self.__microseconds
!         return s
  
      days = property(lambda self: self.__days, doc="days")
***************
*** 560,568 ****
          "Construct a date from a POSIX timestamp (like time.time())."
          y, m, d, hh, mm, ss, weekday, jday, dst = _time.localtime(t)
-         us = int((t % 1.0) * 1000000)
-         if dst > 0:
-             tz = -(_time.altzone // 60)
-         else:
-             tz = -(_time.timezone // 60)
          return cls(y, m, d)
      fromtimestamp = classmethod(fromtimestamp)
--- 538,541 ----
***************
*** 636,642 ****
      def __hash__(self):
          "Hash."
-         # Caution:  objects that compare equal must have equal hashcodes,
-         # and two dates can be equal even if their fields aren't
-         # (due to tzoffset).  So we have to compute a UTC-normalized hash.
          return hash((self.__year, self.__month, self.__day))
  
--- 609,612 ----
***************
*** 648,662 ****
      # strftime("%c", ...) is locale specific.
  
-     # XXX An additional question is whether ctime() should renormalize
-     # to local time, or display the time as entered (which may be
-     # confusing since it doesn't show the timezone).
- 
      def ctime(self):
!         "Format a la ctime() in local time."
!         t = tmxxx(self.__year, self.__month, self.__day)
!         return t.ctime()
  
      def strftime(self, fmt):
!         "Format using strftime() in local time."
          return _time.strftime(fmt, _time.localtime(self._mktime()))
  
--- 618,627 ----
      # strftime("%c", ...) is locale specific.
  
      def ctime(self):
!         "Format a la ctime()."
!         return tmxxx(self.__year, self.__month, self.__day).ctime()
  
      def strftime(self, fmt):
!         "Format using strftime()."
          return _time.strftime(fmt, _time.localtime(self._mktime()))
  
***************
*** 776,784 ****
  
      Properties (readonly):
!     year, month, day, hour, minute, second, microsecond, tzoffset
      """
  
      def __init__(self, year, month, day, hour=0, minute=0, second=0,
!                  microsecond=0, tzoffset=None):
          """Constructor.
  
--- 741,749 ----
  
      Properties (readonly):
!     year, month, day, hour, minute, second, microsecond
      """
  
      def __init__(self, year, month, day, hour=0, minute=0, second=0,
!                  microsecond=0):
          """Constructor.
  
***************
*** 787,792 ****
          year, month, day (required, base 1)
          hour, minute, second, microsecond (default to zero)
-         tzoffset (minutes east of UTC; defaults to local time)
- 
          """
          super(datetime, self).__init__(year, month, day)
--- 752,755 ----
***************
*** 799,807 ****
          if not 0 <= microsecond <= 999999:
              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)
          # XXX This duplicates __year, __month, __day for convenience :-(
          self.__year = year
--- 762,765 ----
***************
*** 812,816 ****
          self.__second = second
          self.__microsecond = microsecond
-         self.__tzoffset = tzoffset # minutes east of UTC
  
      # Additional constructors
--- 770,773 ----
***************
*** 820,828 ****
          y, m, d, hh, mm, ss, weekday, jday, dst = _time.localtime(t)
          us = int((t % 1.0) * 1000000)
!         if dst > 0:
!             tz = -(_time.altzone // 60)
!         else:
!             tz = -(_time.timezone // 60)
!         return cls(y, m, d, hh, mm, ss, us, tz)
      fromtimestamp = classmethod(fromtimestamp)
  
--- 777,781 ----
          y, m, d, hh, mm, ss, weekday, jday, dst = _time.localtime(t)
          us = int((t % 1.0) * 1000000)
!         return cls(y, m, d, hh, mm, ss, us)
      fromtimestamp = classmethod(fromtimestamp)
  
***************
*** 837,841 ****
          y, m, d, hh, mm, ss, weekday, jday, dst = _time.gmtime(t)
          us = int((t % 1.0) * 1000000)
!         return cls(y, m, d, hh, mm, ss, us, 0)
      utcfromtimestamp = classmethod(utcfromtimestamp)
  
--- 790,794 ----
          y, m, d, hh, mm, ss, weekday, jday, dst = _time.gmtime(t)
          us = int((t % 1.0) * 1000000)
!         return cls(y, m, d, hh, mm, ss, us)
      utcfromtimestamp = classmethod(utcfromtimestamp)
  
***************
*** 855,861 ****
              del L[-1]
          s = ", ".join(map(str, L))
!         return "%s(%s, tzoffset=%d)" % (self.__class__.__name__,
!                                         s,
!                                         self.__tzoffset)
  
      def __str__(self):
--- 808,812 ----
              del L[-1]
          s = ", ".join(map(str, L))
!         return "%s(%s)" % (self.__class__.__name__, s)
  
      def __str__(self):
***************
*** 869,874 ****
      microsecond = property(lambda self: self.__microsecond,
                             doc="microsecond (0-999999)")
-     tzoffset = property(lambda self: self.__tzoffset,
-                         doc="time zone offset in minutes east of UTC")
  
      # Standard conversions, __cmp__, __hash__ (and helpers)
--- 820,823 ----
***************
*** 879,883 ****
          # Helper to return a POSIX-ish timestamp
          t = tmxxx(self.__year, self.__month, self.__day,
!                   self.__hour, self.__minute - self.__tzoffset, self.__second,
                    self.__microsecond)
          return t.time()
--- 828,832 ----
          # Helper to return a POSIX-ish timestamp
          t = tmxxx(self.__year, self.__month, self.__day,
!                   self.__hour, self.__minute, self.__second,
                    self.__microsecond)
          return t.time()
***************
*** 890,923 ****
          "Three-way comparison."
          if isinstance(other, datetime):
!             if self.__tzoffset == other.__tzoffset:
!                 y, m, d = self.__year, self.__month, self.__day
!                 H, M = self.__hour, self.__minute
!                 y2, m2, d2 = other.__year, other.__month, other.__day
!                 H2, M2 = other.__hour, other.__minute
!             else:
!                 y, m, d, H, M = self._utc_ymdHM()
!                 y2, m2, d2, H2, M2 = other._utc_ymdHM()
!             return cmp((y, m, d, H, M,
!                         self.__second, self.__microsecond),
!                        (y2, m2, d2, H2, M2,
!                         other.__second, other.__microsecond))
!         else:
!             raise TypeError, ("can't compare datetime to %s instance" %
!                               type(other).__name__)
! 
!     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):
          "Hash."
!         # Caution:  objects that compare equal must have equal hashcodes,
!         # and two datetimes can be equal even if their fields aren't
!         # (due to tzoffset).  So we have to compute a UTC-normalized hash.
!         # XXX _utc_ymdHM can be expensive; dream up a quicker correct way.
!         y, m, d, H, M = self._utc_ymdHM()
!         return hash((y, m, d, H, M, self.__second, self.__microsecond))
  
      # Formatting methods
--- 839,856 ----
          "Three-way comparison."
          if isinstance(other, datetime):
!             return cmp((self.__year, self.__month, self.__day,
!                         self.__hour, self.__minute, self.__second,
!                         self.__microsecond),
!                        (other.__year, other.__month, other.__day,
!                         other.__hour, other.__minute, other.__second,
!                         other.__microsecond))
!         raise TypeError, ("can't compare datetime to %s instance" %
!                           type(other).__name__)
  
      def __hash__(self):
          "Hash."
!         return hash((self.__year, self.__month, self.__day,
!                      self.__hour, self.__minute, self.__second,
!                      self.__microsecond))
  
      # Formatting methods
***************
*** 933,959 ****
  
      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 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):
-         "Format using strftime() in UTC."
-         return _time.strftime(fmt, _time.gmtime(self._mktime()))
- 
      # Computations
  
--- 866,874 ----
  
      def ctime(self):
!         "Format a la ctime()."
          t = tmxxx(self.__year, self.__month, self.__day, self.__hour,
!                   self.__minute, self.__second)
          return t.ctime()
  
      # Computations
  
***************
*** 971,975 ****
              result = self.__class__(t.year, t.month, t.day,
                                      t.hour, t.minute, t.second,
!                                     t.microsecond, self.__tzoffset)
              return result
          raise TypeError
--- 886,890 ----
              result = self.__class__(t.year, t.month, t.day,
                                      t.hour, t.minute, t.second,
!                                     t.microsecond)
              return result
          raise TypeError
***************
*** 988,996 ****
              days1 = self.toordinal()
              days2 = other.toordinal()
!             secs1 = (self.__second +
!                      (self.__minute - self.__tzoffset) * 60 +
!                      self.__hour * 3600)
              secs2 = (other.__second +
!                      (other.__minute - other.__tzoffset) * 60 +
                       other.__hour * 3600)
              return self.timedelta_class(
--- 903,909 ----
              days1 = self.toordinal()
              days2 = other.toordinal()
!             secs1 = (self.__second + self.__minute * 60 + self.__hour * 3600)
              secs2 = (other.__second +
!                      (other.__minute) * 60 +
                       other.__hour * 3600)
              return self.timedelta_class(
***************
*** 1000,1004 ****
          return NotImplemented
  
!     # ISO formats including time and tzoffset
  
      def isoformat(self, sep='T'):
--- 913,917 ----
          return NotImplemented
  
!     # ISO formats including time
  
      def isoformat(self, sep='T'):
***************
*** 1010,1043 ****
          Optional argument sep specifies the separator between date and
          time, default 'T'.
- 
-         This method does not convert to local time.
          """
!         if self.__tzoffset >= 0:
!             h, m = divmod(self.__tzoffset, 60)
!         else:
!             h, m = divmod(-self.__tzoffset, 60)
!             h = -h
!         return "%04d-%02d-%02d%c%02d:%02d:%02d.%06d%+03d:%02d" % (
              self.__year, self.__month, self.__day,
              sep,
              self.__hour, self.__minute, self.__second,
!             self.__microsecond,
!             h, m)
! 
!     def utcisoformat(self, sep='T'):
!         """Return the time as UTC formatted according to ISO.
! 
!         This is 'YYYY-MM-DD HH:MM:SS.mmmmmmZ'.
! 
!         Optional argument sep specifies the separator between date and
!         time, default 'T'.
!         """
!         y, m, d, hh, mm = self._utc_ymdHM()
!         return "%04d-%02d-%02d%c%02d:%02d:%02d.%06dZ" % (
!             y, m, d, sep, hh, mm, self.__second, self.__microsecond)
  
  
! datetime.min = datetime(1, 1, 1, tzoffset=0)
! datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999, tzoffset=0)
  datetime.resolution = timedelta(microseconds=1)
  
--- 923,936 ----
          Optional argument sep specifies the separator between date and
          time, default 'T'.
          """
!         return "%04d-%02d-%02d%c%02d:%02d:%02d.%06d" % (
              self.__year, self.__month, self.__day,
              sep,
              self.__hour, self.__minute, self.__second,
!             self.__microsecond)
  
  
! datetime.min = datetime(1, 1, 1)
! datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)
  datetime.resolution = timedelta(microseconds=1)
  

Index: test_datetime.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/test_datetime.py,v
retrieving revision 1.37
retrieving revision 1.38
diff -C2 -d -r1.37 -r1.38
*** test_datetime.py	5 Mar 2002 14:14:48 -0000	1.37
--- test_datetime.py	6 Mar 2002 01:25:15 -0000	1.38
***************
*** 327,331 ****
  
      def test_roundtrip(self):
!         for dt in (self.theclass(1, 2, 3, 4, 5, 6, 7, 8),
                     self.theclass.now()):
              # Verify dt -> string -> datetime identity.
--- 327,331 ----
  
      def test_roundtrip(self):
!         for dt in (self.theclass(1, 2, 3, 4, 5, 6, 7),
                     self.theclass.now()):
              # Verify dt -> string -> datetime identity.
***************
*** 337,347 ****
              dt2 = self.theclass(dt.year, dt.month, dt.day,
                                  dt.hour, dt.minute, dt.second,
!                                 dt.microsecond, dt.tzoffset)
              self.assertEqual(dt, dt2)
  
      def test_tz_independent_comparing(self):
!         dt1 = self.theclass(2002, 3, 1, 9, 0, 0, tzoffset=-60)
!         dt2 = self.theclass(2002, 3, 1, 10, 0, 0, tzoffset=-60)
!         dt3 = self.theclass(2002, 3, 1, 10, 0, 0, tzoffset=0)
          self.assertEqual(dt1, dt3)
          self.assert_(dt2 > dt3)
--- 337,347 ----
              dt2 = self.theclass(dt.year, dt.month, dt.day,
                                  dt.hour, dt.minute, dt.second,
!                                 dt.microsecond)
              self.assertEqual(dt, dt2)
  
      def test_tz_independent_comparing(self):
!         dt1 = self.theclass(2002, 3, 1, 9, 0, 0)
!         dt2 = self.theclass(2002, 3, 1, 10, 0, 0)
!         dt3 = self.theclass(2002, 3, 1, 9, 0, 0)
          self.assertEqual(dt1, dt3)
          self.assert_(dt2 > dt3)
***************
*** 352,356 ****
          # so comparing via timestamp necessarily calls some distinct values
          # equal).
!         dt1 = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999998, 0)
          us = timedelta(microseconds=1)
          dt2 = dt1 + us
--- 352,356 ----
          # so comparing via timestamp necessarily calls some distinct values
          # equal).
!         dt1 = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999998)
          us = timedelta(microseconds=1)
          dt2 = dt1 + us
***************
*** 358,369 ****
          self.assert_(dt1 < dt2)
  
-         # Again, but mix timezones.
-         dt1 = self.theclass(MAXYEAR, 12, 31, 22, 59, 59, 999998, -60)
-         dt2 = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999998, 0)
-         self.assertEqual(dt1, dt2)
-         dt2 += us
-         self.assertEqual(dt2 - dt1, us)
-         self.assert_(dt1 < dt2)
- 
      def test_bad_constructor_arguments(self):
          # bad years
--- 358,361 ----
***************
*** 410,425 ****
                            2000, 1, 31, 23, 59, 59,
                            1000000)
-         # bad tzoffet
-         self.theclass(2, 1, 1, 0, 0, 0, 0, -1439)    # no exception
-         self.theclass(2, 1, 1, 0, 0, 0, 0,  1439)   # no exception
-         self.assertRaises(ValueError, self.theclass,
-                           2, 1, 1, 0, 0, 0, 0, -1440)
-         self.assertRaises(ValueError, self.theclass,
-                           2, 1, 1, 0, 0, 0, 0,  1440)
  
      def test_hash_equality(self):
!         d = self.theclass(2000, 12, 31, 23, 30, 17, tzoffset=-35)
!         # same thing in UTC.
!         e = self.theclass(2001,  1,  1,  0,  5, 17, tzoffset=0)
          self.assertEqual(d, e)
          self.assertEqual(hash(d), hash(e))
--- 402,409 ----
                            2000, 1, 31, 23, 59, 59,
                            1000000)
  
      def test_hash_equality(self):
!         d = self.theclass(2000, 12, 31, 23, 30, 17)
!         e = self.theclass(2000, 12, 31, 23, 30, 17)
          self.assertEqual(d, e)
          self.assertEqual(hash(d), hash(e))
***************
*** 431,437 ****
          self.assertEqual(dic[e], 2)
  
!         d = self.theclass(2001,  1,  1,  0,  5, 17, tzoffset=35)
!         # same thing in UTC.
!         e = self.theclass(2000, 12, 31, 23, 30, 17, tzoffset=0)
          self.assertEqual(d, e)
          self.assertEqual(hash(d), hash(e))
--- 415,420 ----
          self.assertEqual(dic[e], 2)
  
!         d = self.theclass(2001,  1,  1,  0,  5, 17)
!         e = self.theclass(2001,  1,  1,  0,  5, 17)
          self.assertEqual(d, e)
          self.assertEqual(hash(d), hash(e))
***************
*** 498,506 ****
  
      def test_isoformat(self):
!         t = self.theclass(2, 3, 2, 4, 5, 1, 123, tzoffset=-120)
!         self.assertEqual(t.isoformat(),    "0002-03-02T04:05:01.000123-02:00")
!         self.assertEqual(t.isoformat(' '), "0002-03-02 04:05:01.000123-02:00")
!         self.assertEqual(t.utcisoformat(),    "0002-03-02T06:05:01.000123Z")
!         self.assertEqual(t.utcisoformat(' '), "0002-03-02 06:05:01.000123Z")
  
      def test_tmxxx(self):
--- 481,488 ----
  
      def test_isoformat(self):
!         t = self.theclass(2, 3, 2, 4, 5, 1, 123)
!         self.assertEqual(t.isoformat(),    "0002-03-02T04:05:01.000123")
!         self.assertEqual(t.isoformat('T'), "0002-03-02T04:05:01.000123")
!         self.assertEqual(t.isoformat(' '), "0002-03-02 04:05:01.000123")
  
      def test_tmxxx(self):
***************
*** 514,518 ****
                         (3*60 - 12) * 1000000)
              dt2 = self.theclass(tm.year, tm.month, tm.day, tm.hour, tm.minute,
!                                 tm.second, tm.microsecond, tzoffset=0)
              self.assertEqual(dt, dt2)
              self.assertEqual(timestamp, tm.time())
--- 496,500 ----
                         (3*60 - 12) * 1000000)
              dt2 = self.theclass(tm.year, tm.month, tm.day, tm.hour, tm.minute,
!                                 tm.second, tm.microsecond)
              self.assertEqual(dt, dt2)
              self.assertEqual(timestamp, tm.time())
***************
*** 521,535 ****
          t = self.theclass(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()")
  
  
--- 503,506 ----