diff -r ac647c5b5221 Lib/test/test_datetime.py --- a/Lib/test/test_datetime.py Wed Mar 18 21:26:42 2009 +0100 +++ b/Lib/test/test_datetime.py Thu Mar 19 14:56:25 2009 -0500 @@ -38,86 +38,95 @@ ############################################################################# # tzinfo tests -class FixedOffset(tzinfo): - def __init__(self, offset, name, dstoffset=42): - if isinstance(offset, int): - offset = timedelta(minutes=offset) - if isinstance(dstoffset, int): - dstoffset = timedelta(minutes=dstoffset) - self.__offset = offset - self.__name = name - self.__dstoffset = dstoffset - def __repr__(self): - return self.__name.lower() - def utcoffset(self, dt): - return self.__offset - def tzname(self, dt): - return self.__name - def dst(self, dt): - return self.__dstoffset +def fixedoffset_factory(td_class=timedelta): + class FixedOffset(tzinfo): + def __init__(self, offset, name, dstoffset=42, td = td_class): + if isinstance(offset, int): + offset = td(minutes=offset) + if isinstance(dstoffset, int): + dstoffset = td(minutes=dstoffset) + self.__offset = offset + self.__name = name + self.__dstoffset = dstoffset + def __repr__(self): + return self.__name.lower() + def utcoffset(self, dt): + return self.__offset + def tzname(self, dt): + return self.__name + def dst(self, dt): + return self.__dstoffset -class PicklableFixedOffset(FixedOffset): - def __init__(self, offset=None, name=None, dstoffset=None): - FixedOffset.__init__(self, offset, name, dstoffset) + class PicklableFixedOffset(FixedOffset): + def __init__(self, offset=None, name=None, dstoffset=None): + FixedOffset.__init__(self, offset, name, dstoffset) + + return FixedOffset, PicklableFixedOffset class TestTZInfo(unittest.TestCase): + dt_class = datetime + td_class = timedelta + tzi_class = tzinfo + FixedOffset, PicklableFixedOffset = fixedoffset_factory() def test_non_abstractness(self): # In order to allow subclasses to get pickled, the C implementation # wasn't able to get away with having __init__ raise # NotImplementedError. - useless = tzinfo() - dt = datetime.max + useless = self.tzi_class() + dt = self.dt_class.max self.assertRaises(NotImplementedError, useless.tzname, dt) self.assertRaises(NotImplementedError, useless.utcoffset, dt) self.assertRaises(NotImplementedError, useless.dst, dt) def test_subclass_must_override(self): - class NotEnough(tzinfo): + class NotEnough(self.tzi_class): def __init__(self, offset, name): self.__offset = offset self.__name = name - self.failUnless(issubclass(NotEnough, tzinfo)) + self.failUnless(issubclass(NotEnough, self.tzi_class)) ne = NotEnough(3, "NotByALongShot") - self.failUnless(isinstance(ne, tzinfo)) + self.failUnless(isinstance(ne, self.tzi_class)) - dt = datetime.now() + dt = self.dt_class.now() self.assertRaises(NotImplementedError, ne.tzname, dt) self.assertRaises(NotImplementedError, ne.utcoffset, dt) self.assertRaises(NotImplementedError, ne.dst, dt) def test_normal(self): - fo = FixedOffset(3, "Three") - self.failUnless(isinstance(fo, tzinfo)) - for dt in datetime.now(), None: - self.assertEqual(fo.utcoffset(dt), timedelta(minutes=3)) + fo = self.FixedOffset(3, "Three") + self.failUnless(isinstance(fo, self.tzi_class)) + for dt in self.dt_class.now(), None: + self.assertEqual(fo.utcoffset(dt), self.td_class(minutes=3)) self.assertEqual(fo.tzname(dt), "Three") - self.assertEqual(fo.dst(dt), timedelta(minutes=42)) + self.assertEqual(fo.dst(dt), self.td_class(minutes=42)) def test_pickling_base(self): # There's no point to pickling tzinfo objects on their own (they # carry no data), but they need to be picklable anyway else # concrete subclasses can't be pickled. - orig = tzinfo.__new__(tzinfo) - self.failUnless(type(orig) is tzinfo) + orig = self.tzi_class.__new__(self.tzi_class) + self.failUnless(type(orig) is self.tzi_class) for pickler, unpickler, proto in pickle_choices: green = pickler.dumps(orig, proto) derived = unpickler.loads(green) - self.failUnless(type(derived) is tzinfo) + self.failUnless(type(derived) is self.tzi_class) def test_pickling_subclass(self): + global PicklableFixedOffset + PicklableFixedOffset = self.PicklableFixedOffset # Make sure we can pickle/unpickle an instance of a subclass. - offset = timedelta(minutes=-300) - orig = PicklableFixedOffset(offset, 'cookie') - self.failUnless(isinstance(orig, tzinfo)) - self.failUnless(type(orig) is PicklableFixedOffset) + offset = self.td_class(minutes=-300) + orig = self.PicklableFixedOffset(offset, 'cookie') + self.failUnless(isinstance(orig, self.tzi_class)) + self.failUnless(type(orig) is self.PicklableFixedOffset) self.assertEqual(orig.utcoffset(None), offset) self.assertEqual(orig.tzname(None), 'cookie') for pickler, unpickler, proto in pickle_choices: green = pickler.dumps(orig, proto) derived = unpickler.loads(green) - self.failUnless(isinstance(derived, tzinfo)) - self.failUnless(type(derived) is PicklableFixedOffset) + self.failUnless(isinstance(derived, self.tzi_class)) + self.failUnless(type(derived) is self.PicklableFixedOffset) self.assertEqual(derived.utcoffset(None), offset) self.assertEqual(derived.tzname(None), 'cookie') @@ -167,7 +176,7 @@ def test_constructor(self): eq = self.assertEqual - td = timedelta + td = self.theclass # Check keyword args to constructor eq(td(), td(weeks=0, days=0, hours=0, minutes=0, seconds=0, @@ -192,7 +201,7 @@ def test_computations(self): eq = self.assertEqual - td = timedelta + td = self.theclass a = td(7) # One week b = td(0, 60) # One minute @@ -230,7 +239,7 @@ eq(a//3600000, td(0, 0, 7*24*1000)) def test_disallowed_computations(self): - a = timedelta(42) + a = self.theclass(42) # Add/sub ints, longs, floats should be illegal for i in 1, 1, 1.0: @@ -256,33 +265,33 @@ def test_basic_attributes(self): days, seconds, us = 1, 7, 31 - td = timedelta(days, seconds, us) + td = self.theclass(days, seconds, us) self.assertEqual(td.days, days) self.assertEqual(td.seconds, seconds) self.assertEqual(td.microseconds, us) def test_carries(self): - t1 = timedelta(days=100, + t1 = self.theclass(days=100, weeks=-7, hours=-24*(100-49), minutes=-3, seconds=12, microseconds=(3*60 - 12) * 1e6 + 1) - t2 = timedelta(microseconds=1) + t2 = self.theclass(microseconds=1) self.assertEqual(t1, t2) def test_hash_equality(self): - t1 = timedelta(days=100, + t1 = self.theclass(days=100, weeks=-7, hours=-24*(100-49), minutes=-3, seconds=12, microseconds=(3*60 - 12) * 1000000) - t2 = timedelta() + t2 = self.theclass() self.assertEqual(hash(t1), hash(t2)) - t1 += timedelta(weeks=7) - t2 += timedelta(days=7*7) + t1 += self.theclass(weeks=7) + t2 += self.theclass(days=7*7) self.assertEqual(t1, t2) self.assertEqual(hash(t1), hash(t2)) @@ -293,15 +302,15 @@ def test_pickling(self): args = 12, 34, 56 - orig = timedelta(*args) + orig = self.theclass(*args) for pickler, unpickler, proto in pickle_choices: green = pickler.dumps(orig, proto) derived = unpickler.loads(green) self.assertEqual(orig, derived) def test_compare(self): - t1 = timedelta(2, 3, 4) - t2 = timedelta(2, 3, 4) + t1 = self.theclass(2, 3, 4) + t2 = self.theclass(2, 3, 4) self.assertEqual(t1, t2) self.failUnless(t1 <= t2) self.failUnless(t1 >= t2) @@ -310,7 +319,7 @@ self.failUnless(not t1 > t2) for args in (3, 3, 3), (2, 4, 4), (2, 3, 5): - t2 = timedelta(*args) # this is larger than t1 + t2 = self.theclass(*args) # this is larger than t1 self.failUnless(t1 < t2) self.failUnless(t2 > t1) self.failUnless(t1 <= t2) @@ -340,7 +349,7 @@ self.assertRaises(TypeError, lambda: badarg >= t1) def test_str(self): - td = timedelta + td = self.theclass eq = self.assertEqual eq(str(td(1)), "1 day, 0:00:00") @@ -361,10 +370,10 @@ "999999999 days, 23:59:59.999999") def test_roundtrip(self): - for td in (timedelta(days=999999999, hours=23, minutes=59, + for td in (self.theclass(days=999999999, hours=23, minutes=59, seconds=59, microseconds=999999), - timedelta(days=-999999999), - timedelta(days=1, seconds=2, microseconds=3)): + self.theclass(days=-999999999), + self.theclass(days=1, seconds=2, microseconds=3)): # Verify td -> string -> td identity. s = repr(td) @@ -374,35 +383,36 @@ self.assertEqual(td, td2) # Verify identity via reconstructing from pieces. - td2 = timedelta(td.days, td.seconds, td.microseconds) + td2 = self.theclass(td.days, td.seconds, td.microseconds) self.assertEqual(td, td2) def test_resolution_info(self): - self.assert_(isinstance(timedelta.min, timedelta)) - self.assert_(isinstance(timedelta.max, timedelta)) - self.assert_(isinstance(timedelta.resolution, timedelta)) - self.assert_(timedelta.max > timedelta.min) - self.assertEqual(timedelta.min, timedelta(-999999999)) - self.assertEqual(timedelta.max, timedelta(999999999, 24*3600-1, 1e6-1)) - self.assertEqual(timedelta.resolution, timedelta(0, 0, 1)) + self.assert_(isinstance(self.theclass.min, self.theclass)) + self.assert_(isinstance(self.theclass.max, self.theclass)) + self.assert_(isinstance(self.theclass.resolution, self.theclass)) + self.assert_(self.theclass.max > self.theclass.min) + self.assertEqual(self.theclass.min, self.theclass(-999999999)) + self.assertEqual(self.theclass.max, self.theclass(999999999, + 24*3600-1, 1e6-1)) + self.assertEqual(self.theclass.resolution, self.theclass(0, 0, 1)) def test_overflow(self): - tiny = timedelta.resolution + tiny = self.theclass.resolution - td = timedelta.min + tiny + td = self.theclass.min + tiny td -= tiny # no problem self.assertRaises(OverflowError, td.__sub__, tiny) self.assertRaises(OverflowError, td.__add__, -tiny) - td = timedelta.max - tiny + td = self.theclass.max - tiny td += tiny # no problem self.assertRaises(OverflowError, td.__add__, tiny) self.assertRaises(OverflowError, td.__sub__, -tiny) - self.assertRaises(OverflowError, lambda: -timedelta.max) + self.assertRaises(OverflowError, lambda: -self.theclass.max) def test_microsecond_rounding(self): - td = timedelta + td = self.theclass eq = self.assertEqual # Single-field rounding. @@ -423,20 +433,20 @@ eq(td(days=-.4/us_per_day, hours=-.2/us_per_hour), td(microseconds=-1)) def test_massive_normalization(self): - td = timedelta(microseconds=-1) + td = self.theclass(microseconds=-1) self.assertEqual((td.days, td.seconds, td.microseconds), (-1, 24*3600-1, 999999)) def test_bool(self): - self.failUnless(timedelta(1)) - self.failUnless(timedelta(0, 1)) - self.failUnless(timedelta(0, 0, 1)) - self.failUnless(timedelta(microseconds=1)) - self.failUnless(not timedelta(0)) + self.failUnless(self.theclass(1)) + self.failUnless(self.theclass(0, 1)) + self.failUnless(self.theclass(0, 0, 1)) + self.failUnless(self.theclass(microseconds=1)) + self.failUnless(not self.theclass(0)) def test_subclass_timedelta(self): - class T(timedelta): + class T(self.theclass): @staticmethod def from_td(td): return T(td.days, td.seconds, td.microseconds) @@ -456,7 +466,7 @@ self.assertEqual(t2.as_hours(), -25) t3 = t1 + t2 - self.assert_(type(t3) is timedelta) + self.assert_(type(t3) is self.theclass) t4 = T.from_td(t3) self.assert_(type(t4) is T) self.assertEqual(t3.days, t4.days) @@ -472,12 +482,15 @@ # Tests here won't pass if also run on datetime objects, so don't # subclass this to test datetimes too. + theclass = date + td_class = timedelta + def test_delta_non_days_ignored(self): - dt = date(2000, 1, 2) - delta = timedelta(days=1, hours=2, minutes=3, seconds=4, + dt = self.theclass(2000, 1, 2) + delta = self.td_class(days=1, hours=2, minutes=3, seconds=4, microseconds=5) - days = timedelta(delta.days) - self.assertEqual(days, timedelta(1)) + days = self.td_class(delta.days) + self.assertEqual(days, self.td_class(1)) dt2 = dt + delta self.assertEqual(dt2, dt + days) @@ -489,8 +502,8 @@ self.assertEqual(dt2, dt - days) delta = -delta - days = timedelta(delta.days) - self.assertEqual(days, timedelta(-2)) + days = self.td_class(delta.days) + self.assertEqual(days, self.td_class(-2)) dt2 = dt + delta self.assertEqual(dt2, dt + days) @@ -509,6 +522,7 @@ # few tests that TestDateTime overrides. theclass = date + td_class = timedelta def test_basic_attributes(self): dt = self.theclass(2002, 3, 1) @@ -586,7 +600,7 @@ self.assertRaises(ValueError, lambda: a.fromordinal(aord - 1)) - b = a + timedelta(days=1) + b = a + self.td_class(days=1) self.assertEqual(b.toordinal(), aord + 1) self.assertEqual(b, self.theclass.fromordinal(aord + 1)) @@ -598,7 +612,7 @@ self.assertRaises(ValueError, lambda: a.fromordinal(aord + 1)) - b = a - timedelta(days=1) + b = a - self.td_class(days=1) self.assertEqual(b.toordinal(), aord - 1) self.assertEqual(b, self.theclass.fromordinal(aord - 1)) @@ -658,8 +672,8 @@ self.assertEqual(diff.seconds, 0) self.assertEqual(diff.microseconds, 0) - day = timedelta(1) - week = timedelta(7) + day = self.td_class(1) + week = self.td_class(7) a = self.theclass(2002, 3, 2) self.assertEqual(a + day, self.theclass(2002, 3, 3)) self.assertEqual(day + a, self.theclass(2002, 3, 3)) @@ -756,7 +770,7 @@ # It worked or it didn't. If it didn't, assume it's reason #2, and # let the test pass if they're within half a second of each other. self.failUnless(today == todayagain or - abs(todayagain - today) < timedelta(seconds=0.5)) + abs(todayagain - today) < self.td_class(seconds=0.5)) def test_weekday(self): for i in range(7): @@ -773,13 +787,13 @@ for i in range(7): d = self.theclass(2003, 12, 22+i) self.assertEqual(d.isocalendar(), (2003, 52, i+1)) - d = self.theclass(2003, 12, 29) + timedelta(i) + d = self.theclass(2003, 12, 29) + self.td_class(i) self.assertEqual(d.isocalendar(), (2004, 1, i+1)) d = self.theclass(2004, 1, 5+i) self.assertEqual(d.isocalendar(), (2004, 2, i+1)) d = self.theclass(2009, 12, 21+i) self.assertEqual(d.isocalendar(), (2009, 52, i+1)) - d = self.theclass(2009, 12, 28) + timedelta(i) + d = self.theclass(2009, 12, 28) + self.td_class(i) self.assertEqual(d.isocalendar(), (2009, 53, i+1)) d = self.theclass(2010, 1, 4+i) self.assertEqual(d.isocalendar(), (2010, 1, i+1)) @@ -893,7 +907,7 @@ def test_resolution_info(self): self.assert_(isinstance(self.theclass.min, self.theclass)) self.assert_(isinstance(self.theclass.max, self.theclass)) - self.assert_(isinstance(self.theclass.resolution, timedelta)) + self.assert_(isinstance(self.theclass.resolution, self.td_class)) self.assert_(self.theclass.max > self.theclass.min) def test_extreme_timedelta(self): @@ -901,7 +915,7 @@ # 3652058 days, 23 hours, 59 minutes, 59 seconds, 999999 microseconds n = (big.days*24*3600 + big.seconds)*1000000 + big.microseconds # n == 315537897599999999 ~= 2**58.13 - justasbig = timedelta(0, 0, n) + justasbig = self.td_class(0, 0, n) self.assertEqual(big, justasbig) self.assertEqual(self.theclass.min + big, self.theclass.max) self.assertEqual(self.theclass.max - big, self.theclass.min) @@ -1107,7 +1121,7 @@ # fields, but does check the month field. This stops, e.g., # datetime.datetime('1995-03-25') from yielding an insane object. base = b'1995-03-25' - if not issubclass(self.theclass, datetime): + if not issubclass(self.theclass, datetime): # XXX base = base[:4] for month_byte in b'9', b'\0', b'\r', b'\xff': self.assertRaises(TypeError, self.theclass, @@ -1127,6 +1141,11 @@ class TestDateTime(TestDate): theclass = datetime + date_class = date + td_class = timedelta + tzi_class = tzinfo + time_class = time + FixedOffset, PicklableFixedOffset = fixedoffset_factory() def test_basic_attributes(self): dt = self.theclass(2002, 3, 1, 12, 0) @@ -1236,14 +1255,14 @@ # so comparing via timestamp necessarily calls some distinct values # equal). dt1 = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999998) - us = timedelta(microseconds=1) + us = self.td_class(microseconds=1) dt2 = dt1 + us self.assertEqual(dt2 - dt1, us) self.assert_(dt1 < dt2) def test_strftime_with_bad_tzname_replace(self): # verify ok if tzinfo.tzname().replace() returns a non-string - class MyTzInfo(FixedOffset): + class MyTzInfo(self.FixedOffset): def tzname(self, dt): class MyStr(str): def replace(self, *args): @@ -1328,10 +1347,10 @@ self.assertEqual(diff.seconds, 0) self.assertEqual(diff.microseconds, 0) a = self.theclass(2002, 3, 2, 17, 6) - millisec = timedelta(0, 0, 1000) - hour = timedelta(0, 3600) - day = timedelta(1) - week = timedelta(7) + millisec = self.td_class(0, 0, 1000) + hour = self.td_class(0, 3600) + day = self.td_class(1) + week = self.td_class(7) self.assertEqual(a + hour, self.theclass(2002, 3, 2, 18, 6)) self.assertEqual(hour + a, self.theclass(2002, 3, 2, 18, 6)) self.assertEqual(a + 10*hour, self.theclass(2002, 3, 3, 3, 6)) @@ -1513,7 +1532,7 @@ # Call it a success if utcnow() and utcfromtimestamp() are within # a second of each other. - tolerance = timedelta(seconds=1) + tolerance = self.td_class(seconds=1) for dummy in range(3): from_now = self.theclass.utcnow() from_timestamp = self.theclass.utcfromtimestamp(time.time()) @@ -1540,7 +1559,8 @@ (t.year, t.month, t.day, t.hour, t.minute, t.second, t.weekday(), - t.toordinal() - date(t.year, 1, 1).toordinal() + 1, + t.toordinal() - + self.date_class(t.year, 1, 1).toordinal() + 1, -1)) tt = t.timetuple() self.assertEqual(tt.tm_year, t.year) @@ -1551,7 +1571,7 @@ self.assertEqual(tt.tm_sec, t.second) self.assertEqual(tt.tm_wday, t.weekday()) self.assertEqual(tt.tm_yday, t.toordinal() - - date(t.year, 1, 1).toordinal() + 1) + self.date_class(t.year, 1, 1).toordinal() + 1) self.assertEqual(tt.tm_isdst, -1) def test_more_strftime(self): @@ -1562,12 +1582,12 @@ def test_extract(self): dt = self.theclass(2002, 3, 4, 18, 45, 3, 1234) - self.assertEqual(dt.date(), date(2002, 3, 4)) - self.assertEqual(dt.time(), time(18, 45, 3, 1234)) + self.assertEqual(dt.date(), self.date_class(2002, 3, 4)) + self.assertEqual(dt.time(), self.time_class(18, 45, 3, 1234)) def test_combine(self): - d = date(2002, 3, 4) - t = time(18, 45, 3, 1234) + d = self.date_class(2002, 3, 4) + t = self.time_class(18, 45, 3, 1234) expected = self.theclass(2002, 3, 4, 18, 45, 3, 1234) combine = self.theclass.combine dt = combine(d, t) @@ -1615,21 +1635,22 @@ # Pretty boring! The TZ test is more interesting here. astimezone() # simply can't be applied to a naive object. dt = self.theclass.now() - f = FixedOffset(44, "") + td_class = self.td_class + f = self.FixedOffset(44, "") self.assertRaises(TypeError, dt.astimezone) # not enough args self.assertRaises(TypeError, dt.astimezone, f, f) # too many args self.assertRaises(TypeError, dt.astimezone, dt) # arg wrong type self.assertRaises(ValueError, dt.astimezone, f) # naive self.assertRaises(ValueError, dt.astimezone, tz=f) # naive - class Bogus(tzinfo): + class Bogus(self.tzi_class): def utcoffset(self, dt): return None - def dst(self, dt): return timedelta(0) + def dst(self, dt): return td_class(0) bog = Bogus() self.assertRaises(ValueError, dt.astimezone, bog) # naive - class AlsoBogus(tzinfo): - def utcoffset(self, dt): return timedelta(0) + class AlsoBogus(self.tzi_class): + def utcoffset(self, dt): return td_class(0) def dst(self, dt): return None alsobog = AlsoBogus() self.assertRaises(ValueError, dt.astimezone, alsobog) # also naive @@ -1667,6 +1688,7 @@ class TestTime(HarmlessMixedComparison, unittest.TestCase): theclass = time + td_class = timedelta def test_basic_attributes(self): t = self.theclass(12, 0) @@ -1878,7 +1900,7 @@ def test_resolution_info(self): self.assert_(isinstance(self.theclass.min, self.theclass)) self.assert_(isinstance(self.theclass.max, self.theclass)) - self.assert_(isinstance(self.theclass.resolution, timedelta)) + self.assert_(isinstance(self.theclass.resolution, self.td_class)) self.assert_(self.theclass.max > self.theclass.min) def test_pickling(self): @@ -1969,21 +1991,27 @@ # must be legit (which is true for time and datetime). class TZInfoBase: + dt_class = datetime + td_class = timedelta + tzi_class = tzinfo + time_class = time + def test_argument_passing(self): cls = self.theclass + td_class = self.td_class # A datetime passes itself on, a time passes None. - class introspective(tzinfo): + class introspective(self.tzi_class): def tzname(self, dt): return dt and "real" or "none" def utcoffset(self, dt): - return timedelta(minutes = dt and 42 or -42) + return td_class(minutes = dt and 42 or -42) dst = utcoffset obj = cls(1, 2, 3, tzinfo=introspective()) - expected = cls is time and "none" or "real" + expected = cls is self.time_class and "none" or "real" self.assertEqual(obj.tzname(), expected) - expected = timedelta(minutes=(cls is time and -42 or 42)) + expected = self.td_class(minutes=(cls is self.time_class and -42 or 42)) self.assertEqual(obj.utcoffset(), expected) self.assertEqual(obj.dst(), expected) @@ -1996,7 +2024,7 @@ def utcoffset(self, dt): pass self.assertRaises(TypeError, cls, 1, 1, 1, tzinfo=NiceTry) - class BetterTry(tzinfo): + class BetterTry(self.tzi_class): def __init__(self): pass def utcoffset(self, dt): pass b = BetterTry() @@ -2004,9 +2032,10 @@ self.failUnless(t.tzinfo is b) def test_utc_offset_out_of_bounds(self): - class Edgy(tzinfo): + td_class = self.td_class + class Edgy(self.tzi_class): def __init__(self, offset): - self.offset = timedelta(minutes=offset) + self.offset = td_class(minutes=offset) def utcoffset(self, dt): return self.offset @@ -2015,9 +2044,9 @@ (-1439, True), (1439, True), (1440, False)): - if cls is time: + if cls is self.time_class: t = cls(1, 2, 3, tzinfo=Edgy(offset)) - elif cls is datetime: + elif cls is self.dt_class: t = cls(6, 6, 6, 1, 2, 3, tzinfo=Edgy(offset)) else: assert 0, "impossible" @@ -2025,7 +2054,7 @@ aofs = abs(offset) h, m = divmod(aofs, 60) tag = "%c%02d:%02d" % (offset < 0 and '-' or '+', h, m) - if isinstance(t, datetime): + if isinstance(t, self.dt_class): t = t.timetz() self.assertEqual(str(t), "01:02:03" + tag) else: @@ -2033,7 +2062,8 @@ def test_tzinfo_classes(self): cls = self.theclass - class C1(tzinfo): + td_class = self.td_class + class C1(self.tzi_class): def utcoffset(self, dt): return None def dst(self, dt): return None def tzname(self, dt): return None @@ -2044,17 +2074,17 @@ self.failUnless(t.dst() is None) self.failUnless(t.tzname() is None) - class C3(tzinfo): - def utcoffset(self, dt): return timedelta(minutes=-1439) - def dst(self, dt): return timedelta(minutes=1439) + class C3(self.tzi_class): + def utcoffset(self, dt): return td_class(minutes=-1439) + def dst(self, dt): return td_class(minutes=1439) def tzname(self, dt): return "aname" t = cls(1, 1, 1, tzinfo=C3()) - self.assertEqual(t.utcoffset(), timedelta(minutes=-1439)) - self.assertEqual(t.dst(), timedelta(minutes=1439)) + self.assertEqual(t.utcoffset(), self.td_class(minutes=-1439)) + self.assertEqual(t.dst(), self.td_class(minutes=1439)) self.assertEqual(t.tzname(), "aname") # Wrong types. - class C4(tzinfo): + class C4(self.tzi_class): def utcoffset(self, dt): return "aname" def dst(self, dt): return 7 def tzname(self, dt): return 0 @@ -2064,34 +2094,35 @@ self.assertRaises(TypeError, t.tzname) # Offset out of range. - class C6(tzinfo): - def utcoffset(self, dt): return timedelta(hours=-24) - def dst(self, dt): return timedelta(hours=24) + class C6(self.tzi_class): + def utcoffset(self, dt): return td_class(hours=-24) + def dst(self, dt): return td_class(hours=24) t = 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) + class C7(self.tzi_class): + def utcoffset(self, dt): return td_class(seconds=61) + def dst(self, dt): return td_class(microseconds=-81) t = cls(1, 1, 1, tzinfo=C7()) self.assertRaises(ValueError, t.utcoffset) self.assertRaises(ValueError, t.dst) def test_aware_compare(self): cls = self.theclass + td_class = self.td_class # Ensure that utcoffset() gets ignored if the comparands have # the same tzinfo member. - class OperandDependentOffset(tzinfo): + class OperandDependentOffset(self.tzi_class): def utcoffset(self, t): if t.minute < 10: # d0 and d1 equal after adjustment - return timedelta(minutes=t.minute) + return td_class(minutes=t.minute) else: # d2 off in the weeds - return timedelta(minutes=59) + return td_class(minutes=59) base = cls(8, 9, 10, tzinfo=OperandDependentOffset()) d0 = base.replace(minute=3) @@ -2108,7 +2139,7 @@ # Note that a time can't actually have an operand-depedent offset, # though (and time.utcoffset() passes None to tzinfo.utcoffset()), # so skip this test for time. - if cls is not time: + if cls is not self.time_class: d0 = base.replace(minute=3, tzinfo=OperandDependentOffset()) d1 = base.replace(minute=9, tzinfo=OperandDependentOffset()) d2 = base.replace(minute=11, tzinfo=OperandDependentOffset()) @@ -2130,6 +2161,9 @@ # Testing time objects with a non-None tzinfo. class TestTimeTZ(TestTime, TZInfoBase, unittest.TestCase): theclass = time + td_class = timedelta + tzi_class = tzinfo + FixedOffset, PicklableFixedOffset = fixedoffset_factory() def test_empty(self): t = self.theclass() @@ -2140,14 +2174,14 @@ self.failUnless(t.tzinfo is None) def test_zones(self): - est = FixedOffset(-300, "EST", 1) - utc = FixedOffset(0, "UTC", -2) - met = FixedOffset(60, "MET", 3) - t1 = time( 7, 47, tzinfo=est) - t2 = time(12, 47, tzinfo=utc) - t3 = time(13, 47, tzinfo=met) - t4 = time(microsecond=40) - t5 = time(microsecond=40, tzinfo=utc) + est = self.FixedOffset(-300, "EST", 1) + utc = self.FixedOffset(0, "UTC", -2) + met = self.FixedOffset(60, "MET", 3) + t1 = self.theclass( 7, 47, tzinfo=est) + t2 = self.theclass(12, 47, tzinfo=utc) + t3 = self.theclass(13, 47, tzinfo=met) + t4 = self.theclass(microsecond=40) + t5 = self.theclass(microsecond=40, tzinfo=utc) self.assertEqual(t1.tzinfo, est) self.assertEqual(t2.tzinfo, utc) @@ -2155,9 +2189,9 @@ self.failUnless(t4.tzinfo is None) 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.assertEqual(t1.utcoffset(), self.td_class(minutes=-300)) + self.assertEqual(t2.utcoffset(), self.td_class(minutes=0)) + self.assertEqual(t3.utcoffset(), self.td_class(minutes=60)) self.failUnless(t4.utcoffset() is None) self.assertRaises(TypeError, t1.utcoffset, "no args") @@ -2167,9 +2201,9 @@ self.failUnless(t4.tzname() is None) 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.assertEqual(t1.dst(), self.td_class(minutes=1)) + self.assertEqual(t2.dst(), self.td_class(minutes=-2)) + self.assertEqual(t3.dst(), self.td_class(minutes=3)) self.failUnless(t4.dst() is None) self.assertRaises(TypeError, t1.dst, "no args") @@ -2196,7 +2230,7 @@ self.assertEqual(t4.isoformat(), "00:00:00.000040") self.assertEqual(t5.isoformat(), "00:00:00.000040+00:00") - d = 'datetime.time' + d = 'datetime.' + self.theclass.__name__ self.assertEqual(repr(t1), d + "(7, 47, tzinfo=est)") self.assertEqual(repr(t2), d + "(12, 47, tzinfo=utc)") self.assertEqual(repr(t3), d + "(13, 47, tzinfo=met)") @@ -2208,29 +2242,31 @@ self.assertEqual(t2.strftime("%H:%M:%S %Z %z"), "12:47:00 UTC +0000") self.assertEqual(t3.strftime("%H:%M:%S %Z %z"), "13:47:00 MET +0100") - yuck = FixedOffset(-1439, "%z %Z %%z%%Z") - t1 = time(23, 59, tzinfo=yuck) + yuck = self.FixedOffset(-1439, "%z %Z %%z%%Z") + t1 = self.theclass(23, 59, tzinfo=yuck) self.assertEqual(t1.strftime("%H:%M %%Z='%Z' %%z='%z'"), "23:59 %Z='%z %Z %%z%%Z' %z='-2359'") # Check that an invalid tzname result raises an exception. - class Badtzname(tzinfo): + class Badtzname(self.tzi_class): def tzname(self, dt): return 42 - t = time(2, 3, 4, tzinfo=Badtzname()) + t = self.theclass(2, 3, 4, tzinfo=Badtzname()) self.assertEqual(t.strftime("%H:%M:%S"), "02:03:04") self.assertRaises(TypeError, t.strftime, "%Z") def test_hash_edge_cases(self): # Offsets that overflow a basic time. - t1 = self.theclass(0, 1, 2, 3, tzinfo=FixedOffset(1439, "")) - t2 = self.theclass(0, 0, 2, 3, tzinfo=FixedOffset(1438, "")) + t1 = self.theclass(0, 1, 2, 3, tzinfo=self.FixedOffset(1439, "")) + t2 = self.theclass(0, 0, 2, 3, tzinfo=self.FixedOffset(1438, "")) self.assertEqual(hash(t1), hash(t2)) - t1 = self.theclass(23, 58, 6, 100, tzinfo=FixedOffset(-1000, "")) - t2 = self.theclass(23, 48, 6, 100, tzinfo=FixedOffset(-1010, "")) + t1 = self.theclass(23, 58, 6, 100, tzinfo=self.FixedOffset(-1000, "")) + t2 = self.theclass(23, 48, 6, 100, tzinfo=self.FixedOffset(-1010, "")) self.assertEqual(hash(t1), hash(t2)) def test_pickling(self): + global PicklableFixedOffset + PicklableFixedOffset = self.PicklableFixedOffset # Try one without a tzinfo. args = 20, 59, 16, 64**2 orig = self.theclass(*args) @@ -2240,48 +2276,49 @@ self.assertEqual(orig, derived) # Try one with a tzinfo. - tinfo = PicklableFixedOffset(-300, 'cookie') + tinfo = self.PicklableFixedOffset(-300, 'cookie') orig = self.theclass(5, 6, 7, tzinfo=tinfo) for pickler, unpickler, proto in pickle_choices: green = pickler.dumps(orig, proto) derived = unpickler.loads(green) self.assertEqual(orig, derived) - self.failUnless(isinstance(derived.tzinfo, PicklableFixedOffset)) - self.assertEqual(derived.utcoffset(), timedelta(minutes=-300)) + self.failUnless(isinstance(derived.tzinfo, + self.PicklableFixedOffset)) + self.assertEqual(derived.utcoffset(), self.td_class(minutes=-300)) self.assertEqual(derived.tzname(), 'cookie') def test_more_bool(self): # Test cases with non-None tzinfo. cls = self.theclass - t = cls(0, tzinfo=FixedOffset(-300, "")) + t = cls(0, tzinfo=self.FixedOffset(-300, "")) self.failUnless(t) - t = cls(5, tzinfo=FixedOffset(-300, "")) + t = cls(5, tzinfo=self.FixedOffset(-300, "")) self.failUnless(t) - t = cls(5, tzinfo=FixedOffset(300, "")) + t = cls(5, tzinfo=self.FixedOffset(300, "")) self.failUnless(not t) - t = cls(23, 59, tzinfo=FixedOffset(23*60 + 59, "")) + t = cls(23, 59, tzinfo=self.FixedOffset(23*60 + 59, "")) self.failUnless(not t) # Mostly ensuring this doesn't overflow internally. - t = cls(0, tzinfo=FixedOffset(23*60 + 59, "")) + t = cls(0, tzinfo=self.FixedOffset(23*60 + 59, "")) self.failUnless(t) # But this should yield a value error -- the utcoffset is bogus. - t = cls(0, tzinfo=FixedOffset(24*60, "")) + t = cls(0, tzinfo=self.FixedOffset(24*60, "")) self.assertRaises(ValueError, lambda: bool(t)) # Likewise. - t = cls(0, tzinfo=FixedOffset(-24*60, "")) + t = cls(0, tzinfo=self.FixedOffset(-24*60, "")) self.assertRaises(ValueError, lambda: bool(t)) def test_replace(self): cls = self.theclass - z100 = FixedOffset(100, "+100") - zm200 = FixedOffset(timedelta(minutes=-200), "-200") + z100 = self.FixedOffset(100, "+100") + zm200 = self.FixedOffset(self.td_class(minutes=-200), "-200") args = [1, 2, 3, 4, z100] base = cls(*args) self.assertEqual(base, base.replace()) @@ -2318,29 +2355,30 @@ self.assertRaises(ValueError, base.replace, microsecond=1000000) def test_mixed_compare(self): - t1 = time(1, 2, 3) - t2 = time(1, 2, 3) + t1 = self.theclass(1, 2, 3) + t2 = self.theclass(1, 2, 3) self.assertEqual(t1, t2) t2 = t2.replace(tzinfo=None) self.assertEqual(t1, t2) - t2 = t2.replace(tzinfo=FixedOffset(None, "")) + t2 = t2.replace(tzinfo=self.FixedOffset(None, "")) self.assertEqual(t1, t2) - t2 = t2.replace(tzinfo=FixedOffset(0, "")) + t2 = t2.replace(tzinfo=self.FixedOffset(0, "")) self.assertRaises(TypeError, lambda: t1 == t2) # In time w/ identical tzinfo objects, utcoffset is ignored. - class Varies(tzinfo): + td_class = self.td_class + class Varies(self.tzi_class): def __init__(self): - self.offset = timedelta(minutes=22) + self.offset = td_class(minutes=22) def utcoffset(self, t): - self.offset += timedelta(minutes=1) + self.offset += td_class(minutes=1) return self.offset v = Varies() t1 = t2.replace(tzinfo=v) t2 = t2.replace(tzinfo=v) - self.assertEqual(t1.utcoffset(), timedelta(minutes=23)) - self.assertEqual(t2.utcoffset(), timedelta(minutes=24)) + self.assertEqual(t1.utcoffset(), self.td_class(minutes=23)) + self.assertEqual(t2.utcoffset(), self.td_class(minutes=24)) self.assertEqual(t1, t2) # But if they're not identical, it isn't ignored. @@ -2362,7 +2400,7 @@ def newmeth(self, start): return start + self.hour + self.second - args = 4, 5, 6, 500, FixedOffset(-300, "EST", 1) + args = 4, 5, 6, 500, self.FixedOffset(-300, "EST", 1) dt1 = self.theclass(*args) dt2 = C(*args, **{'extra': 7}) @@ -2378,6 +2416,11 @@ class TestDateTimeTZ(TestDateTime, TZInfoBase, unittest.TestCase): theclass = datetime + date_class = date + td_class = timedelta + tzi_class = tzinfo + time_class = time + FixedOffset, PicklableFixedOffset = fixedoffset_factory() def test_trivial(self): dt = self.theclass(1, 2, 3, 4, 5, 6, 7) @@ -2395,10 +2438,10 @@ # and TestDateTime covered non-tzinfo cases. # Smallest possible after UTC adjustment. - t1 = self.theclass(1, 1, 1, tzinfo=FixedOffset(1439, "")) + t1 = self.theclass(1, 1, 1, tzinfo=self.FixedOffset(1439, "")) # Largest possible after UTC adjustment. t2 = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999999, - tzinfo=FixedOffset(-1439, "")) + tzinfo=self.FixedOffset(-1439, "")) # Make sure those compare correctly, and w/o overflow. self.failUnless(t1 < t2) @@ -2409,25 +2452,26 @@ self.assertEqual(t2, t2) # Equal afer adjustment. - t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(1, "")) - t2 = self.theclass(2, 1, 1, 3, 13, tzinfo=FixedOffset(3*60+13+2, "")) + t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=self.FixedOffset(1, "")) + t2 = self.theclass(2, 1, 1, 3, 13, + tzinfo=self.FixedOffset(3*60+13+2, "")) self.assertEqual(t1, t2) # Change t1 not to subtract a minute, and t1 should be larger. - t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(0, "")) + t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=self.FixedOffset(0, "")) self.failUnless(t1 > t2) # Change t1 to subtract 2 minutes, and t1 should be smaller. - t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(2, "")) + t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=self.FixedOffset(2, "")) self.failUnless(t1 < t2) # Back to the original t1, but make seconds resolve it. - t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(1, ""), + t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=self.FixedOffset(1, ""), second=1) self.failUnless(t1 > t2) # Likewise, but make microseconds resolve it. - t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(1, ""), + t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=self.FixedOffset(1, ""), microsecond=1) self.failUnless(t1 > t2) @@ -2437,7 +2481,7 @@ self.assertEqual(t2, t2) # It's also naive if it has tzinfo but tzinfo.utcoffset() is None. - class Naive(tzinfo): + class Naive(self.tzi_class): def utcoffset(self, dt): return None t2 = self.theclass(5, 6, 7, tzinfo=Naive()) self.assertRaises(TypeError, lambda: t1 == t2) @@ -2448,15 +2492,18 @@ t1 = self.theclass(5, 6, 7) self.assertEqual(t1, t2) + td_class = self.td_class # Try a bogus uctoffset. - class Bogus(tzinfo): + class Bogus(self.tzi_class): def utcoffset(self, dt): - return timedelta(minutes=1440) # out of bounds + return td_class(minutes=1440) # out of bounds t1 = self.theclass(2, 2, 2, tzinfo=Bogus()) - t2 = self.theclass(2, 2, 2, tzinfo=FixedOffset(0, "")) + t2 = self.theclass(2, 2, 2, tzinfo=self.FixedOffset(0, "")) self.assertRaises(ValueError, lambda: t1 == t2) def test_pickling(self): + global PicklableFixedOffset + PicklableFixedOffset = self.PicklableFixedOffset # Try one without a tzinfo. args = 6, 7, 23, 20, 59, 1, 64**2 orig = self.theclass(*args) @@ -2466,45 +2513,45 @@ self.assertEqual(orig, derived) # Try one with a tzinfo. - tinfo = PicklableFixedOffset(-300, 'cookie') + tinfo = self.PicklableFixedOffset(-300, 'cookie') orig = self.theclass(*args, **{'tzinfo': tinfo}) - derived = self.theclass(1, 1, 1, tzinfo=FixedOffset(0, "", 0)) + derived = self.theclass(1, 1, 1, tzinfo=self.FixedOffset(0, "", 0)) for pickler, unpickler, proto in pickle_choices: green = pickler.dumps(orig, proto) derived = unpickler.loads(green) self.assertEqual(orig, derived) self.failUnless(isinstance(derived.tzinfo, - PicklableFixedOffset)) - self.assertEqual(derived.utcoffset(), timedelta(minutes=-300)) + self.PicklableFixedOffset)) + self.assertEqual(derived.utcoffset(), self.td_class(minutes=-300)) self.assertEqual(derived.tzname(), 'cookie') def test_extreme_hashes(self): # If an attempt is made to hash these via subtracting the offset # then hashing a datetime object, OverflowError results. The # Python implementation used to blow up here. - t = self.theclass(1, 1, 1, tzinfo=FixedOffset(1439, "")) + t = self.theclass(1, 1, 1, tzinfo=self.FixedOffset(1439, "")) hash(t) t = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999999, - tzinfo=FixedOffset(-1439, "")) + tzinfo=self.FixedOffset(-1439, "")) hash(t) # OTOH, an OOB offset should blow up. - t = self.theclass(5, 5, 5, tzinfo=FixedOffset(-1440, "")) + t = self.theclass(5, 5, 5, tzinfo=self.FixedOffset(-1440, "")) self.assertRaises(ValueError, hash, t) def test_zones(self): - est = FixedOffset(-300, "EST") - utc = FixedOffset(0, "UTC") - met = FixedOffset(60, "MET") - t1 = datetime(2002, 3, 19, 7, 47, tzinfo=est) - t2 = datetime(2002, 3, 19, 12, 47, tzinfo=utc) - t3 = datetime(2002, 3, 19, 13, 47, tzinfo=met) + est = self.FixedOffset(-300, "EST") + utc = self.FixedOffset(0, "UTC") + met = self.FixedOffset(60, "MET") + t1 = self.theclass(2002, 3, 19, 7, 47, tzinfo=est) + t2 = self.theclass(2002, 3, 19, 12, 47, tzinfo=utc) + t3 = self.theclass(2002, 3, 19, 13, 47, tzinfo=met) self.assertEqual(t1.tzinfo, est) 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.utcoffset(), self.td_class(minutes=-300)) + self.assertEqual(t2.utcoffset(), self.td_class(minutes=0)) + self.assertEqual(t3.utcoffset(), self.td_class(minutes=60)) self.assertEqual(t1.tzname(), "EST") self.assertEqual(t2.tzname(), "UTC") self.assertEqual(t3.tzname(), "MET") @@ -2517,31 +2564,32 @@ self.assertEqual(str(t1), "2002-03-19 07:47:00-05:00") self.assertEqual(str(t2), "2002-03-19 12:47:00+00:00") self.assertEqual(str(t3), "2002-03-19 13:47:00+01:00") - d = 'datetime.datetime(2002, 3, 19, ' + d = 'datetime.datetime(2002, 3, 19, ' # XXX self.assertEqual(repr(t1), d + "7, 47, tzinfo=est)") self.assertEqual(repr(t2), d + "12, 47, tzinfo=utc)") self.assertEqual(repr(t3), d + "13, 47, tzinfo=met)") def test_combine(self): - met = FixedOffset(60, "MET") - d = date(2002, 3, 4) - tz = time(18, 45, 3, 1234, tzinfo=met) - dt = datetime.combine(d, tz) - self.assertEqual(dt, datetime(2002, 3, 4, 18, 45, 3, 1234, - tzinfo=met)) + met = self.FixedOffset(60, "MET") + d = self.date_class(2002, 3, 4) + tz = self.time_class(18, 45, 3, 1234, tzinfo=met) + dt = self.theclass.combine(d, tz) + self.assertEqual(dt, self.theclass(2002, 3, 4, 18, 45, 3, 1234, + tzinfo=met)) def test_extract(self): - met = FixedOffset(60, "MET") + met = self.FixedOffset(60, "MET") dt = self.theclass(2002, 3, 4, 18, 45, 3, 1234, tzinfo=met) - self.assertEqual(dt.date(), date(2002, 3, 4)) - self.assertEqual(dt.time(), time(18, 45, 3, 1234)) - self.assertEqual(dt.timetz(), time(18, 45, 3, 1234, tzinfo=met)) + self.assertEqual(dt.date(), self.date_class(2002, 3, 4)) + self.assertEqual(dt.time(), self.time_class(18, 45, 3, 1234)) + self.assertEqual(dt.timetz(), self.time_class(18, 45, 3, 1234, + tzinfo=met)) def test_tz_aware_arithmetic(self): import random now = self.theclass.now() - tz55 = FixedOffset(-330, "west 5:30") + tz55 = self.FixedOffset(-330, "west 5:30") timeaware = now.time().replace(tzinfo=tz55) nowaware = self.theclass.combine(now.date(), timeaware) self.failUnless(nowaware.tzinfo is tz55) @@ -2557,11 +2605,11 @@ self.assertRaises(TypeError, lambda: nowaware + nowaware) # Subtracting should yield 0. - self.assertEqual(now - now, timedelta(0)) - self.assertEqual(nowaware - nowaware, timedelta(0)) + self.assertEqual(now - now, self.td_class(0)) + self.assertEqual(nowaware - nowaware, self.td_class(0)) # Adding a delta should preserve tzinfo. - delta = timedelta(weeks=1, minutes=12, microseconds=5678) + delta = self.td_class(weeks=1, minutes=12, microseconds=5678) nowawareplus = nowaware + delta self.failUnless(nowaware.tzinfo is tz55) nowawareplus2 = delta + nowaware @@ -2577,7 +2625,8 @@ self.assertEqual(nowawareplus - nowaware, delta) # Make up a random timezone. - tzr = FixedOffset(random.randrange(-1439, 1440), "randomtimezone") + tzr = self.FixedOffset(random.randrange(-1439, 1440), + "randomtimezone") # Attach it to nowawareplus. nowawareplus = nowawareplus.replace(tzinfo=tzr) self.failUnless(nowawareplus.tzinfo is tzr) @@ -2592,23 +2641,23 @@ self.assertEqual(got, expected) # Try max possible difference. - min = self.theclass(1, 1, 1, tzinfo=FixedOffset(1439, "min")) + min = self.theclass(1, 1, 1, tzinfo=self.FixedOffset(1439, "min")) max = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999999, - tzinfo=FixedOffset(-1439, "max")) + tzinfo=self.FixedOffset(-1439, "max")) maxdiff = max - min self.assertEqual(maxdiff, self.theclass.max - self.theclass.min + - timedelta(minutes=2*1439)) + self.td_class(minutes=2*1439)) def test_tzinfo_now(self): meth = self.theclass.now # Ensure it doesn't require tzinfo (i.e., that this doesn't blow up). base = meth() # Try with and without naming the keyword. - off42 = FixedOffset(42, "42") + off42 = self.FixedOffset(42, "42") another = meth(off42) again = meth(tz=off42) self.failUnless(another.tzinfo is again.tzinfo) - self.assertEqual(another.utcoffset(), timedelta(minutes=42)) + self.assertEqual(another.utcoffset(), self.td_class(minutes=42)) # Bad argument with and w/o naming the keyword. self.assertRaises(TypeError, meth, 16) self.assertRaises(TypeError, meth, tzinfo=16) @@ -2620,14 +2669,15 @@ # We don't know which time zone we're in, and don't have a tzinfo # class to represent it, so seeing whether a tz argument actually # does a conversion is tricky. - weirdtz = FixedOffset(timedelta(hours=15, minutes=58), "weirdtz", 0) - utc = FixedOffset(0, "utc", 0) + weirdtz = self.FixedOffset(self.td_class(hours=15, minutes=58), + "weirdtz", 0) + utc = self.FixedOffset(0, "utc", 0) for dummy in range(3): - now = datetime.now(weirdtz) + now = self.theclass.now(weirdtz) self.failUnless(now.tzinfo is weirdtz) - utcnow = datetime.utcnow().replace(tzinfo=utc) + utcnow = self.theclass.utcnow().replace(tzinfo=utc) now2 = utcnow.astimezone(weirdtz) - if abs(now - now2) < timedelta(seconds=30): + if abs(now - now2) < self.td_class(seconds=30): break # Else the code is broken, or more than 30 seconds passed between # calls; assuming the latter, just try again. @@ -2642,11 +2692,11 @@ # Ensure it doesn't require tzinfo (i.e., that this doesn't blow up). base = meth(ts) # Try with and without naming the keyword. - off42 = FixedOffset(42, "42") + off42 = self.FixedOffset(42, "42") another = meth(ts, off42) again = meth(ts, tz=off42) self.failUnless(another.tzinfo is again.tzinfo) - self.assertEqual(another.utcoffset(), timedelta(minutes=42)) + self.assertEqual(another.utcoffset(), self.td_class(minutes=42)) # Bad argument with and w/o naming the keyword. self.assertRaises(TypeError, meth, ts, 16) self.assertRaises(TypeError, meth, ts, tzinfo=16) @@ -2659,15 +2709,16 @@ # Try to make sure tz= actually does some conversion. timestamp = 1000000000 - utcdatetime = datetime.utcfromtimestamp(timestamp) + utcdatetime = self.theclass.utcfromtimestamp(timestamp) # In POSIX (epoch 1970), that's 2001-09-09 01:46:40 UTC, give or take. # But on some flavor of Mac, it's nowhere near that. So we can't have # any idea here what time that actually is, we can only test that # relative changes match. - utcoffset = timedelta(hours=-15, minutes=39) # arbitrary, but not zero - tz = FixedOffset(utcoffset, "tz", 0) + utcoffset = self.td_class(hours=-15, minutes=39) # arbitrary, but not + # zero + tz = self.FixedOffset(utcoffset, "tz", 0) expected = utcdatetime + utcoffset - got = datetime.fromtimestamp(timestamp, tz) + got = self.theclass.fromtimestamp(timestamp, tz) self.assertEqual(expected, got.replace(tzinfo=None)) def test_tzinfo_utcnow(self): @@ -2676,7 +2727,7 @@ base = meth() # Try with and without naming the keyword; for whatever reason, # utcnow() doesn't accept a tzinfo argument. - off42 = FixedOffset(42, "42") + off42 = self.FixedOffset(42, "42") self.assertRaises(TypeError, meth, off42) self.assertRaises(TypeError, meth, tzinfo=off42) @@ -2688,17 +2739,18 @@ base = meth(ts) # Try with and without naming the keyword; for whatever reason, # utcfromtimestamp() doesn't accept a tzinfo argument. - off42 = FixedOffset(42, "42") + off42 = self.FixedOffset(42, "42") self.assertRaises(TypeError, meth, ts, off42) self.assertRaises(TypeError, meth, ts, tzinfo=off42) def test_tzinfo_timetuple(self): # TestDateTime tested most of this. datetime adds a twist to the # DST flag. - class DST(tzinfo): + td_class = self.td_class + class DST(self.tzi_class): def __init__(self, dstvalue): if isinstance(dstvalue, int): - dstvalue = timedelta(minutes=dstvalue) + dstvalue = td_class(minutes=dstvalue) self.dstvalue = dstvalue def dst(self, dt): return self.dstvalue @@ -2729,10 +2781,11 @@ self.assertRaises(ValueError, cls(1,1,1, tzinfo=DST(-1440)).timetuple) def test_utctimetuple(self): - class DST(tzinfo): + td_class = self.td_class + class DST(self.tzi_class): def __init__(self, dstvalue): if isinstance(dstvalue, int): - dstvalue = timedelta(minutes=dstvalue) + dstvalue = td_class(minutes=dstvalue) self.dstvalue = dstvalue def dst(self, dt): return self.dstvalue @@ -2745,7 +2798,7 @@ class UOFS(DST): def __init__(self, uofs, dofs=None): DST.__init__(self, dofs) - self.uofs = timedelta(minutes=uofs) + self.uofs = td_class(minutes=uofs) def utcoffset(self, dt): return self.uofs @@ -2761,7 +2814,8 @@ self.assertEqual(13, t.tm_min) self.assertEqual(d.second, t.tm_sec) self.assertEqual(d.weekday(), t.tm_wday) - self.assertEqual(d.toordinal() - date(1, 1, 1).toordinal() + 1, + self.assertEqual(d.toordinal() - + self.date_class(1, 1, 1).toordinal() + 1, t.tm_yday) self.assertEqual(0, t.tm_isdst) @@ -2793,10 +2847,10 @@ self.assertEqual(t.tm_isdst, 0) def test_tzinfo_isoformat(self): - zero = FixedOffset(0, "+00:00") - plus = FixedOffset(220, "+03:40") - minus = FixedOffset(-231, "-03:51") - unknown = FixedOffset(None, "") + zero = self.FixedOffset(0, "+00:00") + plus = self.FixedOffset(220, "+03:40") + minus = self.FixedOffset(-231, "-03:51") + unknown = self.FixedOffset(None, "") cls = self.theclass datestr = '0001-02-03' @@ -2815,8 +2869,8 @@ def test_replace(self): cls = self.theclass - z100 = FixedOffset(100, "+100") - zm200 = FixedOffset(timedelta(minutes=-200), "-200") + z100 = self.FixedOffset(100, "+100") + zm200 = self.FixedOffset(self.td_class(minutes=-200), "-200") args = [1, 2, 3, 4, 5, 6, 7, z100] base = cls(*args) self.assertEqual(base, base.replace()) @@ -2854,9 +2908,9 @@ def test_more_astimezone(self): # The inherited test_astimezone covered some trivial and error cases. - fnone = FixedOffset(None, "None") - f44m = FixedOffset(44, "44") - fm5h = FixedOffset(-timedelta(hours=5), "m300") + fnone = self.FixedOffset(None, "None") + f44m = self.FixedOffset(44, "44") + fm5h = self.FixedOffset(-self.td_class(hours=5), "m300") dt = self.theclass.now(tz=f44m) self.failUnless(dt.tzinfo is f44m) @@ -2873,7 +2927,7 @@ # Replacing with different tzinfo does adjust. got = dt.astimezone(fm5h) self.failUnless(got.tzinfo is fm5h) - self.assertEqual(got.utcoffset(), timedelta(hours=-5)) + self.assertEqual(got.utcoffset(), self.td_class(hours=-5)) expected = dt - dt.utcoffset() # in effect, convert to UTC expected += fm5h.utcoffset(dt) # and from there to local time expected = expected.replace(tzinfo=fm5h) # and attach new tzinfo @@ -2885,17 +2939,18 @@ def test_aware_subtract(self): cls = self.theclass + td_class = self.td_class # Ensure that utcoffset() is ignored when the operands have the # same tzinfo member. - class OperandDependentOffset(tzinfo): + class OperandDependentOffset(self.tzi_class): def utcoffset(self, t): if t.minute < 10: # d0 and d1 equal after adjustment - return timedelta(minutes=t.minute) + return td_class(minutes=t.minute) else: # d2 off in the weeds - return timedelta(minutes=59) + return td_class(minutes=59) base = cls(8, 9, 10, 11, 12, 13, 14, tzinfo=OperandDependentOffset()) d0 = base.replace(minute=3) @@ -2904,7 +2959,7 @@ for x in d0, d1, d2: for y in d0, d1, d2: got = x - y - expected = timedelta(minutes=x.minute - y.minute) + expected = self.td_class(minutes=x.minute - y.minute) self.assertEqual(got, expected) # OTOH, if the tzinfo members are distinct, utcoffsets aren't @@ -2917,40 +2972,41 @@ for y in d0, d1, d2: got = x - y if (x is d0 or x is d1) and (y is d0 or y is d1): - expected = timedelta(0) + expected = self.td_class(0) elif x is y is d2: - expected = timedelta(0) + expected = self.td_class(0) elif x is d2: - expected = timedelta(minutes=(11-59)-0) + expected = self.td_class(minutes=(11-59)-0) else: assert y is d2 - expected = timedelta(minutes=0-(11-59)) + expected = self.td_class(minutes=0-(11-59)) self.assertEqual(got, expected) def test_mixed_compare(self): - t1 = datetime(1, 2, 3, 4, 5, 6, 7) - t2 = datetime(1, 2, 3, 4, 5, 6, 7) + t1 = self.theclass(1, 2, 3, 4, 5, 6, 7) + t2 = self.theclass(1, 2, 3, 4, 5, 6, 7) self.assertEqual(t1, t2) t2 = t2.replace(tzinfo=None) self.assertEqual(t1, t2) - t2 = t2.replace(tzinfo=FixedOffset(None, "")) + t2 = t2.replace(tzinfo=self.FixedOffset(None, "")) self.assertEqual(t1, t2) - t2 = t2.replace(tzinfo=FixedOffset(0, "")) + t2 = t2.replace(tzinfo=self.FixedOffset(0, "")) self.assertRaises(TypeError, lambda: t1 == t2) + td_class = self.td_class # In datetime w/ identical tzinfo objects, utcoffset is ignored. - class Varies(tzinfo): + class Varies(self.tzi_class): def __init__(self): - self.offset = timedelta(minutes=22) + self.offset = td_class(minutes=22) def utcoffset(self, t): - self.offset += timedelta(minutes=1) + self.offset += td_class(minutes=1) return self.offset v = Varies() t1 = t2.replace(tzinfo=v) t2 = t2.replace(tzinfo=v) - self.assertEqual(t1.utcoffset(), timedelta(minutes=23)) - self.assertEqual(t2.utcoffset(), timedelta(minutes=24)) + self.assertEqual(t1.utcoffset(), self.td_class(minutes=23)) + self.assertEqual(t2.utcoffset(), self.td_class(minutes=24)) self.assertEqual(t1, t2) # But if they're not identical, it isn't ignored. @@ -2972,7 +3028,7 @@ def newmeth(self, start): return start + self.hour + self.year - args = 2002, 12, 31, 4, 5, 6, 500, FixedOffset(-300, "EST", 1) + args = 2002, 12, 31, 4, 5, 6, 500, self.FixedOffset(-300, "EST", 1) dt1 = self.theclass(*args) dt2 = C(*args, **{'extra': 7}) @@ -2991,78 +3047,89 @@ dt += timedelta(days_to_go) return dt -ZERO = timedelta(0) -HOUR = timedelta(hours=1) -DAY = timedelta(days=1) -# In the US, DST starts at 2am (standard time) on the first Sunday in April. -DSTSTART = datetime(1, 4, 1, 2) -# and ends at 2am (DST time; 1am standard time) on the last Sunday of Oct, -# which is the first Sunday on or after Oct 25. Because we view 1:MM as -# being standard time on that day, there is no spelling in local time of -# the last hour of DST (that's 1:MM DST, but 1:MM is taken as standard time). -DSTEND = datetime(1, 10, 25, 1) +class TestTimezoneConversions(unittest.TestCase): + theclass = datetime + theotherclass = date + td_class = timedelta + tzi_class = tzinfo + FixedOffset, PicklableFixedOffset = fixedoffset_factory(td_class) -class USTimeZone(tzinfo): + ZERO = td_class(0) + HOUR = td_class(hours=1) + DAY = td_class(days=1) - def __init__(self, hours, reprname, stdname, dstname): - self.stdoffset = timedelta(hours=hours) - self.reprname = reprname - self.stdname = stdname - self.dstname = dstname + class USTimeZone(tzi_class): + def __init__(self, hours, reprname, stdname, dstname): + self.stdoffset = self.td_class(hours=hours) + self.reprname = reprname + self.stdname = stdname + self.dstname = dstname - def __repr__(self): - return self.reprname + def __repr__(self): + return self.reprname - def tzname(self, dt): - if self.dst(dt): - return self.dstname - else: - return self.stdname + def tzname(self, dt): + if self.dst(dt): + return self.dstname + else: + return self.stdname - def utcoffset(self, dt): - return self.stdoffset + self.dst(dt) + def utcoffset(self, dt): + return self.stdoffset + self.dst(dt) - def dst(self, dt): - if dt is None or dt.tzinfo is None: - # An exception instead may be sensible here, in one or more of - # the cases. - return ZERO - assert dt.tzinfo is self + def dst(self, dt): + if dt is None or dt.tzinfo is None: + # An exception instead may be sensible here, in one or more of + # the cases. + return self.ZERO + assert dt.tzinfo is self - # Find first Sunday in April. - start = first_sunday_on_or_after(DSTSTART.replace(year=dt.year)) - assert start.weekday() == 6 and start.month == 4 and start.day <= 7 + # Find first Sunday in April. + start = first_sunday_on_or_after(self.DSTSTART.replace( + year=dt.year)) + assert (start.weekday() == 6 and start.month == 4 and + start.day <= 7) - # Find last Sunday in October. - end = first_sunday_on_or_after(DSTEND.replace(year=dt.year)) - assert end.weekday() == 6 and end.month == 10 and end.day >= 25 + # Find last Sunday in October. + end = first_sunday_on_or_after(self.DSTEND.replace(year=dt.year)) + assert end.weekday() == 6 and end.month == 10 and end.day >= 25 - # Can't compare naive to aware objects, so strip the timezone from - # dt first. - if start <= dt.replace(tzinfo=None) < end: - return HOUR - else: - return ZERO + # Can't compare naive to aware objects, so strip the timezone from + # dt first. + if start <= dt.replace(tzinfo=None) < end: + return self.HOUR + else: + return self.ZERO -Eastern = USTimeZone(-5, "Eastern", "EST", "EDT") -Central = USTimeZone(-6, "Central", "CST", "CDT") -Mountain = USTimeZone(-7, "Mountain", "MST", "MDT") -Pacific = USTimeZone(-8, "Pacific", "PST", "PDT") -utc_real = FixedOffset(0, "UTC", 0) -# For better test coverage, we want another flavor of UTC that's west of -# the Eastern and Pacific timezones. -utc_fake = FixedOffset(-12*60, "UTCfake", 0) + # In the US, DST starts at 2am (standard time) on the first Sunday in + # April. + USTimeZone.DSTSTART = theclass(1, 4, 1, 2) + # and ends at 2am (DST time; 1am standard time) on the last Sunday of + # Oct, which is the first Sunday on or after Oct 25. Because we view + # 1:MM as being standard time on that day, there is no spelling in + # local time of the last hour of DST (that's 1:MM DST, but 1:MM is + # taken as standard time). + USTimeZone.DSTEND = theclass(1, 10, 25, 1) + USTimeZone.HOUR = HOUR + USTimeZone.ZERO = ZERO -class TestTimezoneConversions(unittest.TestCase): + USTimeZone.td_class = td_class + Eastern = USTimeZone(-5, "Eastern", "EST", "EDT") + Central = USTimeZone(-6, "Central", "CST", "CDT") + Mountain = USTimeZone(-7, "Mountain", "MST", "MDT") + Pacific = USTimeZone(-8, "Pacific", "PST", "PDT") + utc_real = FixedOffset(0, "UTC", 0) + # For better test coverage, we want another flavor of UTC that's west of + # the Eastern and Pacific timezones. + utc_fake = FixedOffset(-12*60, "UTCfake", 0) + # The DST switch times for 2002, in std time. - dston = datetime(2002, 4, 7, 2) - dstoff = datetime(2002, 10, 27, 1) - - theclass = datetime + dston = theclass(2002, 4, 7, 2) + dstoff = theclass(2002, 10, 27, 1) # Check a time that's inside DST. def checkinside(self, dt, tz, utc, dston, dstoff): - self.assertEqual(dt.dst(), HOUR) + self.assertEqual(dt.dst(), self.HOUR) # Conversion to our own timezone is always an identity. self.assertEqual(dt.astimezone(tz), dt) @@ -3081,10 +3148,10 @@ if dt.date() == dston.date() and dt.hour == 2: # We're in the redundant hour, and coming back from # UTC gives the 1:MM:SS standard-time spelling. - self.assertEqual(there_and_back + HOUR, dt) + self.assertEqual(there_and_back + self.HOUR, dt) # Although during was considered to be in daylight # time, there_and_back is not. - self.assertEqual(there_and_back.dst(), ZERO) + self.assertEqual(there_and_back.dst(), self.ZERO) # They're the same times in UTC. self.assertEqual(there_and_back.astimezone(utc), dt.astimezone(utc)) @@ -3100,21 +3167,21 @@ # daylight time. The hour 1:MM daylight == 0:MM standard can't be # expressed in local time. Nevertheless, we want conversion back # from UTC to mimic the local clock's "repeat an hour" behavior. - nexthour_utc = asutc + HOUR + nexthour_utc = asutc + self.HOUR nexthour_tz = nexthour_utc.astimezone(tz) if dt.date() == dstoff.date() and dt.hour == 0: # We're in the hour before the last DST hour. The last DST hour # is ineffable. We want the conversion back to repeat 1:MM. self.assertEqual(nexthour_tz, dt.replace(hour=1)) - nexthour_utc += HOUR + nexthour_utc += self.HOUR nexthour_tz = nexthour_utc.astimezone(tz) self.assertEqual(nexthour_tz, dt.replace(hour=1)) else: - self.assertEqual(nexthour_tz - dt, HOUR) + self.assertEqual(nexthour_tz - dt, self.HOUR) # Check a time that's outside DST. def checkoutside(self, dt, tz, utc): - self.assertEqual(dt.dst(), ZERO) + self.assertEqual(dt.dst(), self.ZERO) # Conversion to our own timezone is always an identity. self.assertEqual(dt.astimezone(tz), dt) @@ -3132,11 +3199,11 @@ # taken as being daylight time (and 1:MM is taken as being standard # time). dstoff = self.dstoff.replace(tzinfo=tz) - for delta in (timedelta(weeks=13), - DAY, - HOUR, - timedelta(minutes=1), - timedelta(microseconds=1)): + for delta in (self.td_class(weeks=13), + self.DAY, + self.HOUR, + self.td_class(minutes=1), + self.td_class(microseconds=1)): self.checkinside(dston, tz, utc, dston, dstoff) for during in dston + delta, dstoff - delta: @@ -3148,15 +3215,15 @@ def test_easy(self): # Despite the name of this test, the endcases are excruciating. - self.convert_between_tz_and_utc(Eastern, utc_real) - self.convert_between_tz_and_utc(Pacific, utc_real) - self.convert_between_tz_and_utc(Eastern, utc_fake) - self.convert_between_tz_and_utc(Pacific, utc_fake) + self.convert_between_tz_and_utc(self.Eastern, self.utc_real) + self.convert_between_tz_and_utc(self.Pacific, self.utc_real) + self.convert_between_tz_and_utc(self.Eastern, self.utc_fake) + self.convert_between_tz_and_utc(self.Pacific, self.utc_fake) # The next is really dancing near the edge. It works because # Pacific and Eastern are far enough apart that their "problem # hours" don't overlap. - self.convert_between_tz_and_utc(Eastern, Pacific) - self.convert_between_tz_and_utc(Pacific, Eastern) + self.convert_between_tz_and_utc(self.Eastern, self.Pacific) + self.convert_between_tz_and_utc(self.Pacific, self.Eastern) # OTOH, these fail! Don't enable them. The difficulty is that # the edge case tests assume that every hour is representable in # the "utc" class. This is always true for a fixed-offset tzinfo @@ -3172,8 +3239,8 @@ def test_tricky(self): # 22:00 on day before daylight starts. - fourback = self.dston - timedelta(hours=4) - ninewest = FixedOffset(-9*60, "-0900", 0) + fourback = self.dston - self.td_class(hours=4) + ninewest = self.FixedOffset(-9*60, "-0900", 0) fourback = fourback.replace(tzinfo=ninewest) # 22:00-0900 is 7:00 UTC == 2:00 EST == 3:00 DST. Since it's "after # 2", we should get the 3 spelling. @@ -3183,17 +3250,17 @@ # local clock jumps from 1 to 3). The point here is to make sure we # get the 3 spelling. expected = self.dston.replace(hour=3) - got = fourback.astimezone(Eastern).replace(tzinfo=None) + got = fourback.astimezone(self.Eastern).replace(tzinfo=None) self.assertEqual(expected, got) # Similar, but map to 6:00 UTC == 1:00 EST == 2:00 DST. In that # case we want the 1:00 spelling. - sixutc = self.dston.replace(hour=6, tzinfo=utc_real) + sixutc = self.dston.replace(hour=6, tzinfo=self.utc_real) # Now 6:00 "looks like daylight", so the offset wrt Eastern is -4, # and adding -4-0 == -4 gives the 2:00 spelling. We want the 1:00 EST # spelling. expected = self.dston.replace(hour=1) - got = sixutc.astimezone(Eastern).replace(tzinfo=None) + got = sixutc.astimezone(self.Eastern).replace(tzinfo=None) self.assertEqual(expected, got) # Now on the day DST ends, we want "repeat an hour" behavior. @@ -3201,9 +3268,9 @@ # EST 23:MM 0:MM 1:MM 2:MM # EDT 0:MM 1:MM 2:MM 3:MM # wall 0:MM 1:MM 1:MM 2:MM against these - for utc in utc_real, utc_fake: - for tz in Eastern, Pacific: - first_std_hour = self.dstoff - timedelta(hours=2) # 23:MM + for utc in self.utc_real, self.utc_fake: + for tz in self.Eastern, self.Pacific: + first_std_hour = self.dstoff - self.td_class(hours=2) # 23:MM # Convert that to UTC. first_std_hour -= tz.utcoffset(None) # Adjust for possibly fake UTC. @@ -3218,15 +3285,17 @@ asutc = asutcbase.replace(minute=minute) astz = asutc.astimezone(tz) self.assertEqual(astz.replace(tzinfo=None), expected) - asutcbase += HOUR + asutcbase += self.HOUR def test_bogus_dst(self): - class ok(tzinfo): - def utcoffset(self, dt): return HOUR - def dst(self, dt): return HOUR + class ok(self.tzi_class): + def utcoffset(self, dt): return self.HOUR + def dst(self, dt): return self.HOUR - now = self.theclass.now().replace(tzinfo=utc_real) + ok.HOUR = self.HOUR + + now = self.theclass.now().replace(tzinfo=self.utc_real) # Doesn't blow up. now.astimezone(ok()) @@ -3236,17 +3305,19 @@ self.assertRaises(ValueError, now.astimezone, notok()) def test_fromutc(self): - self.assertRaises(TypeError, Eastern.fromutc) # not enough args - now = datetime.utcnow().replace(tzinfo=utc_real) - self.assertRaises(ValueError, Eastern.fromutc, now) # wrong tzinfo - now = now.replace(tzinfo=Eastern) # insert correct tzinfo - enow = Eastern.fromutc(now) # doesn't blow up - self.assertEqual(enow.tzinfo, Eastern) # has right tzinfo member - self.assertRaises(TypeError, Eastern.fromutc, now, now) # too many args - self.assertRaises(TypeError, Eastern.fromutc, date.today()) # wrong type + self.assertRaises(TypeError, self.Eastern.fromutc) # not enough args + now = self.theclass.utcnow().replace(tzinfo=self.utc_real) + self.assertRaises(ValueError, self.Eastern.fromutc, now) # wrong tzinfo + now = now.replace(tzinfo=self.Eastern) # insert correct tzinfo + enow = self.Eastern.fromutc(now) # doesn't blow up + self.assertEqual(enow.tzinfo, self.Eastern) # has right tzinfo member + # too many args + self.assertRaises(TypeError, self.Eastern.fromutc, now, now) + self.assertRaises(TypeError, self.Eastern.fromutc, + self.theotherclass.today()) # wrong type # Always converts UTC to standard time. - class FauxUSTimeZone(USTimeZone): + class FauxUSTimeZone(self.USTimeZone): def fromutc(self, dt): return dt + self.stdoffset FEastern = FauxUSTimeZone(-5, "FEastern", "FEST", "FEDT") @@ -3256,13 +3327,13 @@ # EDT 0:MM 1:MM 2:MM 3:MM 4:MM 5:MM # Check around DST start. - start = self.dston.replace(hour=4, tzinfo=Eastern) + start = self.dston.replace(hour=4, tzinfo=self.Eastern) fstart = start.replace(tzinfo=FEastern) for wall in 23, 0, 1, 3, 4, 5: expected = start.replace(hour=wall) if wall == 23: - expected -= timedelta(days=1) - got = Eastern.fromutc(start) + expected -= self.td_class(days=1) + got = self.Eastern.fromutc(start) self.assertEqual(expected, got) expected = fstart + FEastern.stdoffset @@ -3270,18 +3341,18 @@ self.assertEqual(expected, got) # Ensure astimezone() calls fromutc() too. - got = fstart.replace(tzinfo=utc_real).astimezone(FEastern) + got = fstart.replace(tzinfo=self.utc_real).astimezone(FEastern) self.assertEqual(expected, got) - start += HOUR - fstart += HOUR + start += self.HOUR + fstart += self.HOUR # Check around DST end. - start = self.dstoff.replace(hour=4, tzinfo=Eastern) + start = self.dstoff.replace(hour=4, tzinfo=self.Eastern) fstart = start.replace(tzinfo=FEastern) for wall in 0, 1, 1, 2, 3, 4: expected = start.replace(hour=wall) - got = Eastern.fromutc(start) + got = self.Eastern.fromutc(start) self.assertEqual(expected, got) expected = fstart + FEastern.stdoffset @@ -3289,23 +3360,26 @@ self.assertEqual(expected, got) # Ensure astimezone() calls fromutc() too. - got = fstart.replace(tzinfo=utc_real).astimezone(FEastern) + got = fstart.replace(tzinfo=self.utc_real).astimezone(FEastern) self.assertEqual(expected, got) - start += HOUR - fstart += HOUR + start += self.HOUR + fstart += self.HOUR ############################################################################# # oddballs class Oddballs(unittest.TestCase): + date_class = date + dt_class = datetime + time_class = time def test_bug_1028306(self): # Trying to compare a date to a datetime should act like a mixed- # type comparison, despite that datetime is a subclass of date. - as_date = date.today() - as_datetime = datetime.combine(as_date, time()) + as_date = self.date_class.today() + as_datetime = self.dt_class.combine(as_date, self.time_class()) self.assert_(as_date != as_datetime) self.assert_(as_datetime != as_date) self.assert_(not as_date == as_datetime)