[Python-checkins] python/nondist/sandbox/datetime datetime.py,1.117,1.118 doc.txt,1.63,1.64 test_datetime.py,1.75,1.76

tim_one@users.sourceforge.net tim_one@users.sourceforge.net
Sat, 21 Dec 2002 17:43:16 -0800


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

Modified Files:
	datetime.py doc.txt test_datetime.py 
Log Message:
Relatively massive changes to implement a Wiki suggestion:
{timetz,datetimetz}.{utcoffset,dst}() now return a timetuple (or None)
instead of an int (or None).
tzinfo.{utcoffset,dst)() can now return a timetuple (or an int, or None).
The change is so invasive primarily because the *internals* don't want to
work with timetuples at all, so every internal use of utcoffset() and
dst() had to change.


Index: datetime.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/datetime.py,v
retrieving revision 1.117
retrieving revision 1.118
diff -C2 -d -r1.117 -r1.118
*** datetime.py	21 Dec 2002 17:41:35 -0000	1.117
--- datetime.py	22 Dec 2002 01:43:13 -0000	1.118
***************
*** 165,169 ****
  # Correctly substitute for %z and %Z escapes in strftime formats.
  def _wrap_strftime(object, format, timetuple):
!     # Don't call utcoffset() or tzname() unless actually needed.
      zreplace = None # the string to use for %z
      Zreplace = None # the string to use for %Z
--- 165,169 ----
  # Correctly substitute for %z and %Z escapes in strftime formats.
  def _wrap_strftime(object, format, timetuple):
!     # Don't call _utcoffset() or tzname() unless actually needed.
      zreplace = None # the string to use for %z
      Zreplace = None # the string to use for %Z
***************
*** 183,188 ****
                      if zreplace is None:
                          zreplace = ""
!                         if hasattr(object, "utcoffset"):
!                             offset = object.utcoffset()
                              if offset is not None:
                                  sign = '+'
--- 183,188 ----
                      if zreplace is None:
                          zreplace = ""
!                         if hasattr(object, "_utcoffset"):
!                             offset = object._utcoffset()
                              if offset is not None:
                                  sign = '+'
***************
*** 218,235 ****
      return getattr(tzinfo, methname)(self)
  
  def _check_utc_offset(name, offset):
      if offset is None:
!         return
      if not isinstance(offset, (int, long, timedelta)):
          raise TypeError("tzinfo.%s() must return None, integer "
                          "or timedelta, not '%s'" % (name, type(offset)))
      if -1440 < offset < 1440:
!         return
      raise ValueError("%s()=%d, must be in -1439..1439" % (name, offset))
  
- def _check_tzname(name):
-     if name is not None and not isinstance(name, str):
-         raise TypeError("tzinfo.tzname() must return None or string, "
-                         "not '%s'" % type(name))
  
  # This is a start at a struct tm workalike.  Goals:
--- 218,255 ----
      return getattr(tzinfo, methname)(self)
  
+ # Just raise TypeError if the arg isn't None or a string.
+ def _check_tzname(name):
+     if name is not None and not isinstance(name, str):
+         raise TypeError("tzinfo.tzname() must return None or string, "
+                         "not '%s'" % type(name))
+ 
+ # name is the offset-producing method, "utcoffset" or "dst".
+ # offset is what it returned.
+ # If offset isn't None, int, long, or timedelta, raises TypeError.
+ # If offset is None, returns None.
+ # Else offset is checked for being in range, and a whole # of minutes.
+ # If it is, its integer value is returned.  Else ValueError is raised.
  def _check_utc_offset(name, offset):
+     assert name in ("utcoffset", "dst")
      if offset is None:
!         return None
      if not isinstance(offset, (int, long, timedelta)):
          raise TypeError("tzinfo.%s() must return None, integer "
                          "or timedelta, not '%s'" % (name, type(offset)))
+     if isinstance(offset, timedelta):
+         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))
  
  
  # This is a start at a struct tm workalike.  Goals:
***************
*** 1008,1013 ****
          if mytz is ottz:
              return supercmp(other)
!         myoff = self.utcoffset()
!         otoff = other.utcoffset()
          if myoff == otoff:
              return supercmp(other)
--- 1028,1033 ----
          if mytz is ottz:
              return supercmp(other)
!         myoff = self._utcoffset()
!         otoff = other._utcoffset()
          if myoff == otoff:
              return supercmp(other)
***************
*** 1021,1025 ****
      def __hash__(self):
          """Hash."""
!         tzoff = self.utcoffset()
          if not tzoff: # zero or None!
              return super(timetz, self).__hash__()
--- 1041,1045 ----
      def __hash__(self):
          """Hash."""
!         tzoff = self._utcoffset()
          if not tzoff: # zero or None!
              return super(timetz, self).__hash__()
***************
*** 1035,1039 ****
      def _tzstr(self, sep=":"):
          """Return formatted timezone offset (+xx:xx) or None."""
!         off = self.utcoffset()
          if off is not None:
              if off < 0:
--- 1055,1059 ----
      def _tzstr(self, sep=":"):
          """Return formatted timezone offset (+xx:xx) or None."""
!         off = self._utcoffset()
          if off is not None:
              if off < 0:
***************
*** 1043,1048 ****
                  sign = "+"
              hh, mm = divmod(off, 60)
!             if hh >= 24:
!                 raise ValueError("utcoffset must be in -1439 .. 1439")
              off = "%s%02d%s%02d" % (sign, hh, sep, mm)
          return off
--- 1063,1067 ----
                  sign = "+"
              hh, mm = divmod(off, 60)
!             assert 0 <= hh < 24
              off = "%s%02d%s%02d" % (sign, hh, sep, mm)
          return off
***************
*** 1075,1079 ****
          UTC)."""
          offset = _call_tzinfo_method(self, self.__tzinfo, "utcoffset")
!         _check_utc_offset("utcoffset", offset)
          return offset
  
--- 1094,1106 ----
          UTC)."""
          offset = _call_tzinfo_method(self, self.__tzinfo, "utcoffset")
!         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, self.__tzinfo, "utcoffset")
!         offset = _check_utc_offset("utcoffset", offset)
          return offset
  
***************
*** 1099,1103 ****
          """
          offset = _call_tzinfo_method(self, self.__tzinfo, "dst")
!         _check_utc_offset("dst", offset)
          return offset
  
--- 1126,1138 ----
          """
          offset = _call_tzinfo_method(self, self.__tzinfo, "dst")
!         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).
!     def _dst(self):
!         offset = _call_tzinfo_method(self, self.__tzinfo, "dst")
!         offset = _check_utc_offset("dst", offset)
          return offset
  
***************
*** 1105,1109 ****
          if self.second or self.microsecond:
              return 1
!         offset = self.utcoffset() or 0
          return self.hour * 60 + self.minute - offset != 0
  
--- 1140,1144 ----
          if self.second or self.microsecond:
              return 1
!         offset = self._utcoffset() or 0
          return self.hour * 60 + self.minute - offset != 0
  
***************
*** 1430,1434 ****
      def timetuple(self):
          "Return local time tuple compatible with time.localtime()."
!         dst = self.dst()
          if dst is None:
              dst = -1
--- 1465,1469 ----
      def timetuple(self):
          "Return local time tuple compatible with time.localtime()."
!         dst = self._dst()
          if dst is None:
              dst = -1
***************
*** 1443,1447 ****
          y, m, d = self.year, self.month, self.day
          hh, mm, ss = self.hour, self.minute, self.second
!         offset = self.utcoffset()
          if offset:  # neither None nor 0
              tm = tmxxx(y, m, d, hh, mm - offset)
--- 1478,1482 ----
          y, m, d = self.year, self.month, self.day
          hh, mm, ss = self.hour, self.minute, self.second
!         offset = self._utcoffset()
          if offset:  # neither None nor 0
              tm = tmxxx(y, m, d, hh, mm - offset)
***************
*** 1457,1461 ****
      def isoformat(self, sep='T'):
          s = super(datetimetz, self).isoformat(sep)
!         off = self.utcoffset()
          if off is not None:
              if off < 0:
--- 1492,1496 ----
      def isoformat(self, sep='T'):
          s = super(datetimetz, self).isoformat(sep)
!         off = self._utcoffset()
          if off is not None:
              if off < 0:
***************
*** 1479,1483 ****
          UTC)."""
          offset = _call_tzinfo_method(self, self.__tzinfo, "utcoffset")
!         _check_utc_offset("utcoffset", offset)
          return offset
  
--- 1514,1526 ----
          UTC)."""
          offset = _call_tzinfo_method(self, self.__tzinfo, "utcoffset")
!         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, self.__tzinfo, "utcoffset")
!         offset = _check_utc_offset("utcoffset", offset)
          return offset
  
***************
*** 1503,1507 ****
          """
          offset = _call_tzinfo_method(self, self.__tzinfo, "dst")
!         _check_utc_offset("dst", offset)
          return offset
  
--- 1546,1558 ----
          """
          offset = _call_tzinfo_method(self, self.__tzinfo, "dst")
!         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, self.__tzinfo, "dst")
!         offset = _check_utc_offset("dst", offset)
          return offset
  
***************
*** 1524,1529 ****
          if mytz is ottz:
              return supersub(other)
!         myoff = self.utcoffset()
!         otoff = other.utcoffset()
          if myoff == otoff:
              return supersub(other)
--- 1575,1580 ----
          if mytz is ottz:
              return supersub(other)
!         myoff = self._utcoffset()
!         otoff = other._utcoffset()
          if myoff == otoff:
              return supersub(other)
***************
*** 1538,1545 ****
          superself = super(datetimetz, self)
          supercmp = superself.__cmp__
!         myoff = self.utcoffset()
          otoff = None
          if isinstance(other, datetimetz):
!             otoff = other.utcoffset()
          if myoff == otoff:
              return supercmp(other)
--- 1589,1596 ----
          superself = super(datetimetz, self)
          supercmp = superself.__cmp__
!         myoff = self._utcoffset()
          otoff = None
          if isinstance(other, datetimetz):
!             otoff = other._utcoffset()
          if myoff == otoff:
              return supercmp(other)
***************
*** 1555,1559 ****
  
      def __hash__(self):
!         tzoff = self.utcoffset()
          if tzoff is None:
              return super(datetimetz, self).__hash__()
--- 1606,1610 ----
  
      def __hash__(self):
!         tzoff = self._utcoffset()
          if tzoff is None:
              return super(datetimetz, self).__hash__()

Index: doc.txt
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/doc.txt,v
retrieving revision 1.63
retrieving revision 1.64
diff -C2 -d -r1.63 -r1.64
*** doc.txt	21 Dec 2002 05:03:13 -0000	1.63
--- doc.txt	22 Dec 2002 01:43:13 -0000	1.64
***************
*** 760,766 ****
      tzinfo object represents both time zone and DST adjustments,
      utcoffset() should return their sum.  If the UTC offset isn't known,
!     return None.  Else the value returned must be an int (or long), in
!     the range -1439 to 1439 inclusive (1440 = 24*60; the magnitude of
!     the offset must be less than one day).
  
    - tzname(dt)
--- 760,767 ----
      tzinfo object represents both time zone and DST adjustments,
      utcoffset() should return their sum.  If the UTC offset isn't known,
!     return None.  Else the value returned must be an int, long, or
!     timedelta object, in the range -1439 to 1439 inclusive (1440 = 24*60;
!     the magnitude of the offset must be less than one day, and must be
!     a whole number of minutes).
  
    - tzname(dt)
***************
*** 778,788 ****
      Return the DST offset, in minutes east of UTC, or None if DST
      information isn't known.  Return 0 if DST is not in effect.
!     If DST is in effect, return an int (or long), in the range
!     -1439 to 1439 inclusive.  Note that DST offset, if applicable,
!     has already been added to the UTC offset returned by utcoffset(),
!     so there's no need to consult dst() unless you're interested in
!     displaying DST info separately.  For example, datetimetz.timetuple()
!     calls its tzinfo object's dst() method to determine how the tm_isdst
!     flag should be set.
  
  Example tzinfo classes:
--- 779,790 ----
      Return the DST offset, in minutes east of UTC, or None if DST
      information isn't known.  Return 0 if DST is not in effect.
!     If DST is in effect, return an int, long, or timedelta object, in
!     the range -1439 to 1439 inclusive.  This must be a whole number of
!     minutes.  Note that DST offset, if applicable, has already been added
!     to the UTC offset returned by utcoffset(), so there's no need to
!     consult dst() unless you're interested in displaying DST info
!     separately.  For example, datetimetz.timetuple() calls its
!     tzinfo object's dst() method to determine how the tm_isdst flag
!     should be set.
  
  Example tzinfo classes:
***************
*** 924,928 ****
  
    - utcoffset()
!     If self.tzinfo is None, returns None, else self.tzinfo.utcoffset(self).
  
    - tzname():
--- 926,931 ----
  
    - utcoffset()
!     If self.tzinfo is None, returns None, else self.tzinfo.utcoffset(self),
!     converted a timedelta object.
  
    - tzname():
***************
*** 930,940 ****
  
    - dst()
!     If self.tzinfo is None, returns None, else self.tzinfo.dst(self).
  
  
  class datetimetz
  ================
- XXX I think this is *still* missing some methods from the
- XXX Python implementation.
  A datetimetz object is a single object containing all the information
  from a date object and a timetz object.
--- 933,942 ----
  
    - dst()
!     If self.tzinfo is None, returns None, else self.tzinfo.dst(self),
!     converted to a timedelta object.
  
  
  class datetimetz
  ================
  A datetimetz object is a single object containing all the information
  from a date object and a timetz object.
***************
*** 1073,1076 ****
--- 1075,1079 ----
    - utcoffset()
      If self.tzinfo is None, returns None, else self.tzinfo.utcoffset(self).
+     converted to a timedelta object.
  
    - tzname():
***************
*** 1078,1082 ****
  
    - dst()
!     If self.tzinfo is None, returns None, else self.tzinfo.dst(self).
  
    - timetuple()
--- 1081,1086 ----
  
    - dst()
!     If self.tzinfo is None, returns None, else self.tzinfo.dst(self),
!     converted to a timedelta object.
  
    - timetuple()

Index: test_datetime.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/test_datetime.py,v
retrieving revision 1.75
retrieving revision 1.76
diff -C2 -d -r1.75 -r1.76
*** test_datetime.py	21 Dec 2002 17:41:35 -0000	1.75
--- test_datetime.py	22 Dec 2002 01:43:13 -0000	1.76
***************
*** 1471,1495 ****
          self.failUnless(not cls())
  
! 
! class TestTimeTZ(TestTime):
! 
!     theclass = timetz
! 
!     def test_empty(self):
!         t = self.theclass()
!         self.assertEqual(t.hour, 0)
!         self.assertEqual(t.minute, 0)
!         self.assertEqual(t.second, 0)
!         self.assertEqual(t.microsecond, 0)
!         self.failUnless(t.tzinfo is None)
  
      def test_bad_tzinfo_classes(self):
!         tz = self.theclass
!         self.assertRaises(TypeError, tz, tzinfo=12)
  
          class NiceTry(object):
              def __init__(self): pass
              def utcoffset(self, dt): pass
!         self.assertRaises(TypeError, tz, tzinfo=NiceTry)
  
          class BetterTry(tzinfo):
--- 1471,1487 ----
          self.failUnless(not cls())
  
! # A mixin for classes with a tzinfo= argument.  Subclasses must define
! # theclass as a class atribute, and theclass(1, 1, 1, tzinfo=whatever)
! # must be legit (which is true for timetz and datetimetz).
! class TZInfoBase(unittest.TestCase):
  
      def test_bad_tzinfo_classes(self):
!         cls = self.theclass
!         self.assertRaises(TypeError, cls, 1, 1, 1, tzinfo=12)
  
          class NiceTry(object):
              def __init__(self): pass
              def utcoffset(self, dt): pass
!         self.assertRaises(TypeError, cls, 1, 1, 1, tzinfo=NiceTry)
  
          class BetterTry(tzinfo):
***************
*** 1497,1503 ****
              def utcoffset(self, dt): pass
          b = BetterTry()
!         t = tz(tzinfo=b)
          self.failUnless(t.tzinfo is b)
  
      def test_zones(self):
          est = FixedOffset(-300, "EST", 1)
--- 1489,1588 ----
              def utcoffset(self, dt): pass
          b = BetterTry()
!         t = cls(1, 1, 1, tzinfo=b)
          self.failUnless(t.tzinfo is b)
  
+     def test_utc_offset_out_of_bounds(self):
+         class Edgy(tzinfo):
+             def __init__(self, offset):
+                 self.offset = offset
+             def utcoffset(self, dt):
+                 return self.offset
+ 
+         cls = self.theclass
+         for offset, legit in ((-1440, False),
+                               (-1439, True),
+                               (1439, True),
+                               (1440, False)):
+             if cls is timetz:
+                 t = cls(1, 2, 3, tzinfo=Edgy(offset))
+             elif cls is datetimetz:
+                 t = cls(6, 6, 6, 1, 2, 3, tzinfo=Edgy(offset))
+             if legit:
+                 aofs = abs(offset)
+                 h, m = divmod(aofs, 60)
+                 tag = "%c%02d:%02d" % (offset < 0 and '-' or '+', h, m)
+                 if isinstance(t, datetimetz):
+                     t = t.timetz()
+                 self.assertEqual(str(t), "01:02:03" + tag)
+             else:
+                 self.assertRaises(ValueError, str, t)
+ 
+     def test_tzinfo_classes(self):
+         cls = self.theclass
+         class C1(tzinfo):
+             def utcoffset(self, dt): return None
+             def dst(self, dt): return None
+             def tzname(self, dt): return None
+         for t in (cls(1, 1, 1),
+                   cls(1, 1, 1, tzinfo=None),
+                   cls(1, 1, 1, tzinfo=C1())):
+             self.failUnless(t.utcoffset() is None)
+             self.failUnless(t.dst() is None)
+             self.failUnless(t.tzname() is None)
+ 
+         class C2(tzinfo):
+             def utcoffset(self, dt): return -1439
+             def dst(self, dt): return 1439
+             def tzname(self, dt): return "aname"
+         class C3(tzinfo):
+             def utcoffset(self, dt): return timedelta(minutes=-1439)
+             def dst(self, dt): return timedelta(minutes=1439)
+             def tzname(self, dt): return "aname"
+         for t in cls(1, 1, 1, tzinfo=C2()), cls(1, 1, 1, tzinfo=C3()):
+             self.assertEqual(t.utcoffset(), timedelta(minutes=-1439))
+             self.assertEqual(t.dst(), timedelta(minutes=1439))
+             self.assertEqual(t.tzname(), "aname")
+ 
+         # Wrong types.
+         class C4(tzinfo):
+             def utcoffset(self, dt): return "aname"
+             def dst(self, dt): return ()
+             def tzname(self, dt): return 0
+         t = cls(1, 1, 1, tzinfo=C4())
+         self.assertRaises(TypeError, t.utcoffset)
+         self.assertRaises(TypeError, t.dst)
+         self.assertRaises(TypeError, t.tzname)
+ 
+         # Offset out of range.
+         class C5(tzinfo):
+             def utcoffset(self, dt): return -1440
+             def dst(self, dt): return 1440
+         class C6(tzinfo):
+             def utcoffset(self, dt): return timedelta(hours=-24)
+             def dst(self, dt): return timedelta(hours=24)
+         for t in cls(1, 1, 1, tzinfo=C5()), cls(1, 1, 1, tzinfo=C6()):
+             self.assertRaises(ValueError, t.utcoffset)
+             self.assertRaises(ValueError, t.dst)
+ 
+         # Not a whole number of minutes.
+         class C7(tzinfo):
+             def utcoffset(self, dt): return timedelta(seconds=61)
+             def dst(self, dt): return timedelta(microseconds=-81)
+         t = cls(1, 1, 1, tzinfo=C7())
+         self.assertRaises(ValueError, t.utcoffset)
+         self.assertRaises(ValueError, t.dst)
+ 
+ 
+ class TestTimeTZ(TestTime, TZInfoBase):
+     theclass = timetz
+ 
+     def test_empty(self):
+         t = self.theclass()
+         self.assertEqual(t.hour, 0)
+         self.assertEqual(t.minute, 0)
+         self.assertEqual(t.second, 0)
+         self.assertEqual(t.microsecond, 0)
+         self.failUnless(t.tzinfo is None)
+ 
      def test_zones(self):
          est = FixedOffset(-300, "EST", 1)
***************
*** 1516,1522 ****
          self.assertEqual(t5.tzinfo, utc)
  
!         self.assertEqual(t1.utcoffset(), -300)
!         self.assertEqual(t2.utcoffset(), 0)
!         self.assertEqual(t3.utcoffset(), 60)
          self.failUnless(t4.utcoffset() is None)
          self.assertRaises(TypeError, t1.utcoffset, "no args")
--- 1601,1607 ----
          self.assertEqual(t5.tzinfo, utc)
  
!         self.assertEqual(t1.utcoffset(), timedelta(minutes=-300))
!         self.assertEqual(t2.utcoffset(), timedelta(minutes=0))
!         self.assertEqual(t3.utcoffset(), timedelta(minutes=60))
          self.failUnless(t4.utcoffset() is None)
          self.assertRaises(TypeError, t1.utcoffset, "no args")
***************
*** 1528,1534 ****
          self.assertRaises(TypeError, t1.tzname, "no args")
  
!         self.assertEqual(t1.dst(), 1)
!         self.assertEqual(t2.dst(), -2)
!         self.assertEqual(t3.dst(), 3)
          self.failUnless(t4.dst() is None)
          self.assertRaises(TypeError, t1.dst, "no args")
--- 1613,1619 ----
          self.assertRaises(TypeError, t1.tzname, "no args")
  
!         self.assertEqual(t1.dst(), timedelta(minutes=1))
!         self.assertEqual(t2.dst(), timedelta(minutes=-2))
!         self.assertEqual(t3.dst(), timedelta(minutes=3))
          self.failUnless(t4.dst() is None)
          self.assertRaises(TypeError, t1.dst, "no args")
***************
*** 1591,1614 ****
          self.assertEqual(hash(t1), hash(t2))
  
-     def test_utc_offset_out_of_bounds(self):
-         class Edgy(tzinfo):
-             def __init__(self, offset):
-                 self.offset = offset
-             def utcoffset(self, dt):
-                 return self.offset
- 
-         for offset, legit in ((-1440, False),
-                               (-1439, True),
-                               (1439, True),
-                               (1440, False)):
-             t = timetz(1, 2, 3, tzinfo=Edgy(offset))
-             if legit:
-                 aofs = abs(offset)
-                 h, m = divmod(aofs, 60)
-                 tag = "%c%02d:%02d" % (offset < 0 and '-' or '+', h, m)
-                 self.assertEqual(str(t), "01:02:03" + tag)
-             else:
-                 self.assertRaises(ValueError, str, t)
- 
      def test_pickling(self):
          import pickle, cPickle
--- 1676,1679 ----
***************
*** 1636,1640 ****
          self.assertEqual(orig, derived)
          self.failUnless(isinstance(derived.tzinfo, PicklableFixedOffset))
!         self.assertEqual(derived.utcoffset(), -300)
          self.assertEqual(derived.tzname(), 'cookie')
  
--- 1701,1705 ----
          self.assertEqual(orig, derived)
          self.failUnless(isinstance(derived.tzinfo, PicklableFixedOffset))
!         self.assertEqual(derived.utcoffset(), timedelta(minutes=-300))
          self.assertEqual(derived.tzname(), 'cookie')
  
***************
*** 1646,1650 ****
                  self.failUnless(isinstance(derived.tzinfo,
                                  PicklableFixedOffset))
!                 self.assertEqual(derived.utcoffset(), -300)
                  self.assertEqual(derived.tzname(), 'cookie')
  
--- 1711,1715 ----
                  self.failUnless(isinstance(derived.tzinfo,
                                  PicklableFixedOffset))
!                 self.assertEqual(derived.utcoffset(), timedelta(minutes=-300))
                  self.assertEqual(derived.tzname(), 'cookie')
  
***************
*** 1677,1682 ****
          self.assertRaises(ValueError, lambda: bool(t))
  
! class TestDateTimeTZ(TestDateTime):
! 
      theclass = datetimetz
  
--- 1742,1746 ----
          self.assertRaises(ValueError, lambda: bool(t))
  
! class TestDateTimeTZ(TestDateTime, TZInfoBase):
      theclass = datetimetz
  
***************
*** 1757,1776 ****
          self.assertRaises(ValueError, lambda: t1 == t1)
  
-     def test_bad_tzinfo_classes(self):
-         tz = self.theclass
-         self.assertRaises(TypeError, tz, 1, 2, 3, tzinfo=12)
- 
-         class NiceTry(object):
-             def __init__(self): pass
-             def utcoffset(self, dt): pass
-         self.assertRaises(TypeError, tz, 1, 2, 3, tzinfo=NiceTry)
- 
-         class BetterTry(tzinfo):
-             def __init__(self): pass
-             def utcoffset(self, dt): pass
-         b = BetterTry()
-         t = tz(1, 2, 3, tzinfo=b)
-         self.failUnless(t.tzinfo is b)
- 
      def test_pickling(self):
          import pickle, cPickle
--- 1821,1824 ----
***************
*** 1798,1802 ****
          self.assertEqual(orig, derived)
          self.failUnless(isinstance(derived.tzinfo, PicklableFixedOffset))
!         self.assertEqual(derived.utcoffset(), -300)
          self.assertEqual(derived.tzname(), 'cookie')
  
--- 1846,1850 ----
          self.assertEqual(orig, derived)
          self.failUnless(isinstance(derived.tzinfo, PicklableFixedOffset))
!         self.assertEqual(derived.utcoffset(), timedelta(minutes=-300))
          self.assertEqual(derived.tzname(), 'cookie')
  
***************
*** 1808,1812 ****
                  self.failUnless(isinstance(derived.tzinfo,
                                  PicklableFixedOffset))
!                 self.assertEqual(derived.utcoffset(), -300)
                  self.assertEqual(derived.tzname(), 'cookie')
  
--- 1856,1860 ----
                  self.failUnless(isinstance(derived.tzinfo,
                                  PicklableFixedOffset))
!                 self.assertEqual(derived.utcoffset(), timedelta(minutes=-300))
                  self.assertEqual(derived.tzname(), 'cookie')
  
***************
*** 1835,1841 ****
          self.assertEqual(t2.tzinfo, utc)
          self.assertEqual(t3.tzinfo, met)
!         self.assertEqual(t1.utcoffset(), -300)
!         self.assertEqual(t2.utcoffset(), 0)
!         self.assertEqual(t3.utcoffset(), 60)
          self.assertEqual(t1.tzname(), "EST")
          self.assertEqual(t2.tzname(), "UTC")
--- 1883,1889 ----
          self.assertEqual(t2.tzinfo, utc)
          self.assertEqual(t3.tzinfo, met)
!         self.assertEqual(t1.utcoffset(), timedelta(minutes=-300))
!         self.assertEqual(t2.utcoffset(), timedelta(minutes=0))
!         self.assertEqual(t3.utcoffset(), timedelta(minutes=60))
          self.assertEqual(t1.tzname(), "EST")
          self.assertEqual(t2.tzname(), "UTC")
***************
*** 1927,1932 ****
          #            (nowawareplus offset - nowaware offset) =
          #            -delta + nowawareplus offset - nowaware offset
!         expected = timedelta(minutes=nowawareplus.utcoffset() -
!                                      nowaware.utcoffset()) - delta
          self.assertEqual(got, expected)
  
--- 1975,1979 ----
          #            (nowawareplus offset - nowaware offset) =
          #            -delta + nowawareplus offset - nowaware offset
!         expected = nowawareplus.utcoffset() - nowaware.utcoffset() - delta
          self.assertEqual(got, expected)
  
***************
*** 1948,1952 ****
          again = meth(tzinfo=off42)
          self.failUnless(another.tzinfo is again.tzinfo)
!         self.assertEqual(another.utcoffset(), 42)
          # Bad argument with and w/o naming the keyword.
          self.assertRaises(TypeError, meth, 16)
--- 1995,1999 ----
          again = meth(tzinfo=off42)
          self.failUnless(another.tzinfo is again.tzinfo)
!         self.assertEqual(another.utcoffset(), timedelta(minutes=42))
          # Bad argument with and w/o naming the keyword.
          self.assertRaises(TypeError, meth, 16)
***************
*** 1968,1972 ****
          again = meth(ts, tzinfo=off42)
          self.failUnless(another.tzinfo is again.tzinfo)
!         self.assertEqual(another.utcoffset(), 42)
          # Bad argument with and w/o naming the keyword.
          self.assertRaises(TypeError, meth, ts, 16)
--- 2015,2019 ----
          again = meth(ts, tzinfo=off42)
          self.failUnless(another.tzinfo is again.tzinfo)
!         self.assertEqual(another.utcoffset(), timedelta(minutes=42))
          # Bad argument with and w/o naming the keyword.
          self.assertRaises(TypeError, meth, ts, 16)