PyXR

c:\python24\lib \ test \ test_datetime.py



0001 """Test date/time type.
0002 
0003 See http://www.zope.org/Members/fdrake/DateTimeWiki/TestCases
0004 """
0005 
0006 import sys
0007 import pickle
0008 import cPickle
0009 import unittest
0010 
0011 from test import test_support
0012 
0013 from datetime import MINYEAR, MAXYEAR
0014 from datetime import timedelta
0015 from datetime import tzinfo
0016 from datetime import time
0017 from datetime import date, datetime
0018 
0019 pickle_choices = [(pickler, unpickler, proto)
0020                   for pickler in pickle, cPickle
0021                   for unpickler in pickle, cPickle
0022                   for proto in range(3)]
0023 assert len(pickle_choices) == 2*2*3
0024 
0025 # An arbitrary collection of objects of non-datetime types, for testing
0026 # mixed-type comparisons.
0027 OTHERSTUFF = (10, 10L, 34.5, "abc", {}, [], ())
0028 
0029 
0030 #############################################################################
0031 # module tests
0032 
0033 class TestModule(unittest.TestCase):
0034 
0035     def test_constants(self):
0036         import datetime
0037         self.assertEqual(datetime.MINYEAR, 1)
0038         self.assertEqual(datetime.MAXYEAR, 9999)
0039 
0040 #############################################################################
0041 # tzinfo tests
0042 
0043 class FixedOffset(tzinfo):
0044     def __init__(self, offset, name, dstoffset=42):
0045         if isinstance(offset, int):
0046             offset = timedelta(minutes=offset)
0047         if isinstance(dstoffset, int):
0048             dstoffset = timedelta(minutes=dstoffset)
0049         self.__offset = offset
0050         self.__name = name
0051         self.__dstoffset = dstoffset
0052     def __repr__(self):
0053         return self.__name.lower()
0054     def utcoffset(self, dt):
0055         return self.__offset
0056     def tzname(self, dt):
0057         return self.__name
0058     def dst(self, dt):
0059         return self.__dstoffset
0060 
0061 class PicklableFixedOffset(FixedOffset):
0062     def __init__(self, offset=None, name=None, dstoffset=None):
0063         FixedOffset.__init__(self, offset, name, dstoffset)
0064 
0065 class TestTZInfo(unittest.TestCase):
0066 
0067     def test_non_abstractness(self):
0068         # In order to allow subclasses to get pickled, the C implementation
0069         # wasn't able to get away with having __init__ raise
0070         # NotImplementedError.
0071         useless = tzinfo()
0072         dt = datetime.max
0073         self.assertRaises(NotImplementedError, useless.tzname, dt)
0074         self.assertRaises(NotImplementedError, useless.utcoffset, dt)
0075         self.assertRaises(NotImplementedError, useless.dst, dt)
0076 
0077     def test_subclass_must_override(self):
0078         class NotEnough(tzinfo):
0079             def __init__(self, offset, name):
0080                 self.__offset = offset
0081                 self.__name = name
0082         self.failUnless(issubclass(NotEnough, tzinfo))
0083         ne = NotEnough(3, "NotByALongShot")
0084         self.failUnless(isinstance(ne, tzinfo))
0085 
0086         dt = datetime.now()
0087         self.assertRaises(NotImplementedError, ne.tzname, dt)
0088         self.assertRaises(NotImplementedError, ne.utcoffset, dt)
0089         self.assertRaises(NotImplementedError, ne.dst, dt)
0090 
0091     def test_normal(self):
0092         fo = FixedOffset(3, "Three")
0093         self.failUnless(isinstance(fo, tzinfo))
0094         for dt in datetime.now(), None:
0095             self.assertEqual(fo.utcoffset(dt), timedelta(minutes=3))
0096             self.assertEqual(fo.tzname(dt), "Three")
0097             self.assertEqual(fo.dst(dt), timedelta(minutes=42))
0098 
0099     def test_pickling_base(self):
0100         # There's no point to pickling tzinfo objects on their own (they
0101         # carry no data), but they need to be picklable anyway else
0102         # concrete subclasses can't be pickled.
0103         orig = tzinfo.__new__(tzinfo)
0104         self.failUnless(type(orig) is tzinfo)
0105         for pickler, unpickler, proto in pickle_choices:
0106             green = pickler.dumps(orig, proto)
0107             derived = unpickler.loads(green)
0108             self.failUnless(type(derived) is tzinfo)
0109 
0110     def test_pickling_subclass(self):
0111         # Make sure we can pickle/unpickle an instance of a subclass.
0112         offset = timedelta(minutes=-300)
0113         orig = PicklableFixedOffset(offset, 'cookie')
0114         self.failUnless(isinstance(orig, tzinfo))
0115         self.failUnless(type(orig) is PicklableFixedOffset)
0116         self.assertEqual(orig.utcoffset(None), offset)
0117         self.assertEqual(orig.tzname(None), 'cookie')
0118         for pickler, unpickler, proto in pickle_choices:
0119             green = pickler.dumps(orig, proto)
0120             derived = unpickler.loads(green)
0121             self.failUnless(isinstance(derived, tzinfo))
0122             self.failUnless(type(derived) is PicklableFixedOffset)
0123             self.assertEqual(derived.utcoffset(None), offset)
0124             self.assertEqual(derived.tzname(None), 'cookie')
0125 
0126 #############################################################################
0127 # Base clase for testing a particular aspect of timedelta, time, date and
0128 # datetime comparisons.
0129 
0130 class HarmlessMixedComparison(unittest.TestCase):
0131     # Test that __eq__ and __ne__ don't complain for mixed-type comparisons.
0132 
0133     # Subclasses must define 'theclass', and theclass(1, 1, 1) must be a
0134     # legit constructor.
0135 
0136     def test_harmless_mixed_comparison(self):
0137         me = self.theclass(1, 1, 1)
0138 
0139         self.failIf(me == ())
0140         self.failUnless(me != ())
0141         self.failIf(() == me)
0142         self.failUnless(() != me)
0143 
0144         self.failUnless(me in [1, 20L, [], me])
0145         self.failIf(me not in [1, 20L, [], me])
0146 
0147         self.failUnless([] in [me, 1, 20L, []])
0148         self.failIf([] not in [me, 1, 20L, []])
0149 
0150     def test_harmful_mixed_comparison(self):
0151         me = self.theclass(1, 1, 1)
0152 
0153         self.assertRaises(TypeError, lambda: me < ())
0154         self.assertRaises(TypeError, lambda: me <= ())
0155         self.assertRaises(TypeError, lambda: me > ())
0156         self.assertRaises(TypeError, lambda: me >= ())
0157 
0158         self.assertRaises(TypeError, lambda: () < me)
0159         self.assertRaises(TypeError, lambda: () <= me)
0160         self.assertRaises(TypeError, lambda: () > me)
0161         self.assertRaises(TypeError, lambda: () >= me)
0162 
0163         self.assertRaises(TypeError, cmp, (), me)
0164         self.assertRaises(TypeError, cmp, me, ())
0165 
0166 #############################################################################
0167 # timedelta tests
0168 
0169 class TestTimeDelta(HarmlessMixedComparison):
0170 
0171     theclass = timedelta
0172 
0173     def test_constructor(self):
0174         eq = self.assertEqual
0175         td = timedelta
0176 
0177         # Check keyword args to constructor
0178         eq(td(), td(weeks=0, days=0, hours=0, minutes=0, seconds=0,
0179                     milliseconds=0, microseconds=0))
0180         eq(td(1), td(days=1))
0181         eq(td(0, 1), td(seconds=1))
0182         eq(td(0, 0, 1), td(microseconds=1))
0183         eq(td(weeks=1), td(days=7))
0184         eq(td(days=1), td(hours=24))
0185         eq(td(hours=1), td(minutes=60))
0186         eq(td(minutes=1), td(seconds=60))
0187         eq(td(seconds=1), td(milliseconds=1000))
0188         eq(td(milliseconds=1), td(microseconds=1000))
0189 
0190         # Check float args to constructor
0191         eq(td(weeks=1.0/7), td(days=1))
0192         eq(td(days=1.0/24), td(hours=1))
0193         eq(td(hours=1.0/60), td(minutes=1))
0194         eq(td(minutes=1.0/60), td(seconds=1))
0195         eq(td(seconds=0.001), td(milliseconds=1))
0196         eq(td(milliseconds=0.001), td(microseconds=1))
0197 
0198     def test_computations(self):
0199         eq = self.assertEqual
0200         td = timedelta
0201 
0202         a = td(7) # One week
0203         b = td(0, 60) # One minute
0204         c = td(0, 0, 1000) # One millisecond
0205         eq(a+b+c, td(7, 60, 1000))
0206         eq(a-b, td(6, 24*3600 - 60))
0207         eq(-a, td(-7))
0208         eq(+a, td(7))
0209         eq(-b, td(-1, 24*3600 - 60))
0210         eq(-c, td(-1, 24*3600 - 1, 999000))
0211         eq(abs(a), a)
0212         eq(abs(-a), a)
0213         eq(td(6, 24*3600), a)
0214         eq(td(0, 0, 60*1000000), b)
0215         eq(a*10, td(70))
0216         eq(a*10, 10*a)
0217         eq(a*10L, 10*a)
0218         eq(b*10, td(0, 600))
0219         eq(10*b, td(0, 600))
0220         eq(b*10L, td(0, 600))
0221         eq(c*10, td(0, 0, 10000))
0222         eq(10*c, td(0, 0, 10000))
0223         eq(c*10L, td(0, 0, 10000))
0224         eq(a*-1, -a)
0225         eq(b*-2, -b-b)
0226         eq(c*-2, -c+-c)
0227         eq(b*(60*24), (b*60)*24)
0228         eq(b*(60*24), (60*b)*24)
0229         eq(c*1000, td(0, 1))
0230         eq(1000*c, td(0, 1))
0231         eq(a//7, td(1))
0232         eq(b//10, td(0, 6))
0233         eq(c//1000, td(0, 0, 1))
0234         eq(a//10, td(0, 7*24*360))
0235         eq(a//3600000, td(0, 0, 7*24*1000))
0236 
0237     def test_disallowed_computations(self):
0238         a = timedelta(42)
0239 
0240         # Add/sub ints, longs, floats should be illegal
0241         for i in 1, 1L, 1.0:
0242             self.assertRaises(TypeError, lambda: a+i)
0243             self.assertRaises(TypeError, lambda: a-i)
0244             self.assertRaises(TypeError, lambda: i+a)
0245             self.assertRaises(TypeError, lambda: i-a)
0246 
0247         # Mul/div by float isn't supported.
0248         x = 2.3
0249         self.assertRaises(TypeError, lambda: a*x)
0250         self.assertRaises(TypeError, lambda: x*a)
0251         self.assertRaises(TypeError, lambda: a/x)
0252         self.assertRaises(TypeError, lambda: x/a)
0253         self.assertRaises(TypeError, lambda: a // x)
0254         self.assertRaises(TypeError, lambda: x // a)
0255 
0256         # Divison of int by timedelta doesn't make sense.
0257         # Division by zero doesn't make sense.
0258         for zero in 0, 0L:
0259             self.assertRaises(TypeError, lambda: zero // a)
0260             self.assertRaises(ZeroDivisionError, lambda: a // zero)
0261 
0262     def test_basic_attributes(self):
0263         days, seconds, us = 1, 7, 31
0264         td = timedelta(days, seconds, us)
0265         self.assertEqual(td.days, days)
0266         self.assertEqual(td.seconds, seconds)
0267         self.assertEqual(td.microseconds, us)
0268 
0269     def test_carries(self):
0270         t1 = timedelta(days=100,
0271                        weeks=-7,
0272                        hours=-24*(100-49),
0273                        minutes=-3,
0274                        seconds=12,
0275                        microseconds=(3*60 - 12) * 1e6 + 1)
0276         t2 = timedelta(microseconds=1)
0277         self.assertEqual(t1, t2)
0278 
0279     def test_hash_equality(self):
0280         t1 = timedelta(days=100,
0281                        weeks=-7,
0282                        hours=-24*(100-49),
0283                        minutes=-3,
0284                        seconds=12,
0285                        microseconds=(3*60 - 12) * 1000000)
0286         t2 = timedelta()
0287         self.assertEqual(hash(t1), hash(t2))
0288 
0289         t1 += timedelta(weeks=7)
0290         t2 += timedelta(days=7*7)
0291         self.assertEqual(t1, t2)
0292         self.assertEqual(hash(t1), hash(t2))
0293 
0294         d = {t1: 1}
0295         d[t2] = 2
0296         self.assertEqual(len(d), 1)
0297         self.assertEqual(d[t1], 2)
0298 
0299     def test_pickling(self):
0300         args = 12, 34, 56
0301         orig = timedelta(*args)
0302         for pickler, unpickler, proto in pickle_choices:
0303             green = pickler.dumps(orig, proto)
0304             derived = unpickler.loads(green)
0305             self.assertEqual(orig, derived)
0306 
0307     def test_compare(self):
0308         t1 = timedelta(2, 3, 4)
0309         t2 = timedelta(2, 3, 4)
0310         self.failUnless(t1 == t2)
0311         self.failUnless(t1 <= t2)
0312         self.failUnless(t1 >= t2)
0313         self.failUnless(not t1 != t2)
0314         self.failUnless(not t1 < t2)
0315         self.failUnless(not t1 > t2)
0316         self.assertEqual(cmp(t1, t2), 0)
0317         self.assertEqual(cmp(t2, t1), 0)
0318 
0319         for args in (3, 3, 3), (2, 4, 4), (2, 3, 5):
0320             t2 = timedelta(*args)   # this is larger than t1
0321             self.failUnless(t1 < t2)
0322             self.failUnless(t2 > t1)
0323             self.failUnless(t1 <= t2)
0324             self.failUnless(t2 >= t1)
0325             self.failUnless(t1 != t2)
0326             self.failUnless(t2 != t1)
0327             self.failUnless(not t1 == t2)
0328             self.failUnless(not t2 == t1)
0329             self.failUnless(not t1 > t2)
0330             self.failUnless(not t2 < t1)
0331             self.failUnless(not t1 >= t2)
0332             self.failUnless(not t2 <= t1)
0333             self.assertEqual(cmp(t1, t2), -1)
0334             self.assertEqual(cmp(t2, t1), 1)
0335 
0336         for badarg in OTHERSTUFF:
0337             self.assertEqual(t1 == badarg, False)
0338             self.assertEqual(t1 != badarg, True)
0339             self.assertEqual(badarg == t1, False)
0340             self.assertEqual(badarg != t1, True)
0341 
0342             self.assertRaises(TypeError, lambda: t1 <= badarg)
0343             self.assertRaises(TypeError, lambda: t1 < badarg)
0344             self.assertRaises(TypeError, lambda: t1 > badarg)
0345             self.assertRaises(TypeError, lambda: t1 >= badarg)
0346             self.assertRaises(TypeError, lambda: badarg <= t1)
0347             self.assertRaises(TypeError, lambda: badarg < t1)
0348             self.assertRaises(TypeError, lambda: badarg > t1)
0349             self.assertRaises(TypeError, lambda: badarg >= t1)
0350 
0351     def test_str(self):
0352         td = timedelta
0353         eq = self.assertEqual
0354 
0355         eq(str(td(1)), "1 day, 0:00:00")
0356         eq(str(td(-1)), "-1 day, 0:00:00")
0357         eq(str(td(2)), "2 days, 0:00:00")
0358         eq(str(td(-2)), "-2 days, 0:00:00")
0359 
0360         eq(str(td(hours=12, minutes=58, seconds=59)), "12:58:59")
0361         eq(str(td(hours=2, minutes=3, seconds=4)), "2:03:04")
0362         eq(str(td(weeks=-30, hours=23, minutes=12, seconds=34)),
0363            "-210 days, 23:12:34")
0364 
0365         eq(str(td(milliseconds=1)), "0:00:00.001000")
0366         eq(str(td(microseconds=3)), "0:00:00.000003")
0367 
0368         eq(str(td(days=999999999, hours=23, minutes=59, seconds=59,
0369                    microseconds=999999)),
0370            "999999999 days, 23:59:59.999999")
0371 
0372     def test_roundtrip(self):
0373         for td in (timedelta(days=999999999, hours=23, minutes=59,
0374                              seconds=59, microseconds=999999),
0375                    timedelta(days=-999999999),
0376                    timedelta(days=1, seconds=2, microseconds=3)):
0377 
0378             # Verify td -> string -> td identity.
0379             s = repr(td)
0380             self.failUnless(s.startswith('datetime.'))
0381             s = s[9:]
0382             td2 = eval(s)
0383             self.assertEqual(td, td2)
0384 
0385             # Verify identity via reconstructing from pieces.
0386             td2 = timedelta(td.days, td.seconds, td.microseconds)
0387             self.assertEqual(td, td2)
0388 
0389     def test_resolution_info(self):
0390         self.assert_(isinstance(timedelta.min, timedelta))
0391         self.assert_(isinstance(timedelta.max, timedelta))
0392         self.assert_(isinstance(timedelta.resolution, timedelta))
0393         self.assert_(timedelta.max > timedelta.min)
0394         self.assertEqual(timedelta.min, timedelta(-999999999))
0395         self.assertEqual(timedelta.max, timedelta(999999999, 24*3600-1, 1e6-1))
0396         self.assertEqual(timedelta.resolution, timedelta(0, 0, 1))
0397 
0398     def test_overflow(self):
0399         tiny = timedelta.resolution
0400 
0401         td = timedelta.min + tiny
0402         td -= tiny  # no problem
0403         self.assertRaises(OverflowError, td.__sub__, tiny)
0404         self.assertRaises(OverflowError, td.__add__, -tiny)
0405 
0406         td = timedelta.max - tiny
0407         td += tiny  # no problem
0408         self.assertRaises(OverflowError, td.__add__, tiny)
0409         self.assertRaises(OverflowError, td.__sub__, -tiny)
0410 
0411         self.assertRaises(OverflowError, lambda: -timedelta.max)
0412 
0413     def test_microsecond_rounding(self):
0414         td = timedelta
0415         eq = self.assertEqual
0416 
0417         # Single-field rounding.
0418         eq(td(milliseconds=0.4/1000), td(0))    # rounds to 0
0419         eq(td(milliseconds=-0.4/1000), td(0))    # rounds to 0
0420         eq(td(milliseconds=0.6/1000), td(microseconds=1))
0421         eq(td(milliseconds=-0.6/1000), td(microseconds=-1))
0422 
0423         # Rounding due to contributions from more than one field.
0424         us_per_hour = 3600e6
0425         us_per_day = us_per_hour * 24
0426         eq(td(days=.4/us_per_day), td(0))
0427         eq(td(hours=.2/us_per_hour), td(0))
0428         eq(td(days=.4/us_per_day, hours=.2/us_per_hour), td(microseconds=1))
0429 
0430         eq(td(days=-.4/us_per_day), td(0))
0431         eq(td(hours=-.2/us_per_hour), td(0))
0432         eq(td(days=-.4/us_per_day, hours=-.2/us_per_hour), td(microseconds=-1))
0433 
0434     def test_massive_normalization(self):
0435         td = timedelta(microseconds=-1)
0436         self.assertEqual((td.days, td.seconds, td.microseconds),
0437                          (-1, 24*3600-1, 999999))
0438 
0439     def test_bool(self):
0440         self.failUnless(timedelta(1))
0441         self.failUnless(timedelta(0, 1))
0442         self.failUnless(timedelta(0, 0, 1))
0443         self.failUnless(timedelta(microseconds=1))
0444         self.failUnless(not timedelta(0))
0445 
0446     def test_subclass_timedelta(self):
0447 
0448         class T(timedelta):
0449             def from_td(td):
0450                 return T(td.days, td.seconds, td.microseconds)
0451             from_td = staticmethod(from_td)
0452 
0453             def as_hours(self):
0454                 sum = (self.days * 24 +
0455                        self.seconds / 3600.0 +
0456                        self.microseconds / 3600e6)
0457                 return round(sum)
0458 
0459         t1 = T(days=1)
0460         self.assert_(type(t1) is T)
0461         self.assertEqual(t1.as_hours(), 24)
0462 
0463         t2 = T(days=-1, seconds=-3600)
0464         self.assert_(type(t2) is T)
0465         self.assertEqual(t2.as_hours(), -25)
0466 
0467         t3 = t1 + t2
0468         self.assert_(type(t3) is timedelta)
0469         t4 = T.from_td(t3)
0470         self.assert_(type(t4) is T)
0471         self.assertEqual(t3.days, t4.days)
0472         self.assertEqual(t3.seconds, t4.seconds)
0473         self.assertEqual(t3.microseconds, t4.microseconds)
0474         self.assertEqual(str(t3), str(t4))
0475         self.assertEqual(t4.as_hours(), -1)
0476 
0477 #############################################################################
0478 # date tests
0479 
0480 class TestDateOnly(unittest.TestCase):
0481     # Tests here won't pass if also run on datetime objects, so don't
0482     # subclass this to test datetimes too.
0483 
0484     def test_delta_non_days_ignored(self):
0485         dt = date(2000, 1, 2)
0486         delta = timedelta(days=1, hours=2, minutes=3, seconds=4,
0487                           microseconds=5)
0488         days = timedelta(delta.days)
0489         self.assertEqual(days, timedelta(1))
0490 
0491         dt2 = dt + delta
0492         self.assertEqual(dt2, dt + days)
0493 
0494         dt2 = delta + dt
0495         self.assertEqual(dt2, dt + days)
0496 
0497         dt2 = dt - delta
0498         self.assertEqual(dt2, dt - days)
0499 
0500         delta = -delta
0501         days = timedelta(delta.days)
0502         self.assertEqual(days, timedelta(-2))
0503 
0504         dt2 = dt + delta
0505         self.assertEqual(dt2, dt + days)
0506 
0507         dt2 = delta + dt
0508         self.assertEqual(dt2, dt + days)
0509 
0510         dt2 = dt - delta
0511         self.assertEqual(dt2, dt - days)
0512 
0513 class SubclassDate(date):
0514     sub_var = 1
0515 
0516 class TestDate(HarmlessMixedComparison):
0517     # Tests here should pass for both dates and datetimes, except for a
0518     # few tests that TestDateTime overrides.
0519 
0520     theclass = date
0521 
0522     def test_basic_attributes(self):
0523         dt = self.theclass(2002, 3, 1)
0524         self.assertEqual(dt.year, 2002)
0525         self.assertEqual(dt.month, 3)
0526         self.assertEqual(dt.day, 1)
0527 
0528     def test_roundtrip(self):
0529         for dt in (self.theclass(1, 2, 3),
0530                    self.theclass.today()):
0531             # Verify dt -> string -> date identity.
0532             s = repr(dt)
0533             self.failUnless(s.startswith('datetime.'))
0534             s = s[9:]
0535             dt2 = eval(s)
0536             self.assertEqual(dt, dt2)
0537 
0538             # Verify identity via reconstructing from pieces.
0539             dt2 = self.theclass(dt.year, dt.month, dt.day)
0540             self.assertEqual(dt, dt2)
0541 
0542     def test_ordinal_conversions(self):
0543         # Check some fixed values.
0544         for y, m, d, n in [(1, 1, 1, 1),      # calendar origin
0545                            (1, 12, 31, 365),
0546                            (2, 1, 1, 366),
0547                            # first example from "Calendrical Calculations"
0548                            (1945, 11, 12, 710347)]:
0549             d = self.theclass(y, m, d)
0550             self.assertEqual(n, d.toordinal())
0551             fromord = self.theclass.fromordinal(n)
0552             self.assertEqual(d, fromord)
0553             if hasattr(fromord, "hour"):
0554             # if we're checking something fancier than a date, verify
0555             # the extra fields have been zeroed out
0556                 self.assertEqual(fromord.hour, 0)
0557                 self.assertEqual(fromord.minute, 0)
0558                 self.assertEqual(fromord.second, 0)
0559                 self.assertEqual(fromord.microsecond, 0)
0560 
0561         # Check first and last days of year spottily across the whole
0562         # range of years supported.
0563         for year in xrange(MINYEAR, MAXYEAR+1, 7):
0564             # Verify (year, 1, 1) -> ordinal -> y, m, d is identity.
0565             d = self.theclass(year, 1, 1)
0566             n = d.toordinal()
0567             d2 = self.theclass.fromordinal(n)
0568             self.assertEqual(d, d2)
0569             # Verify that moving back a day gets to the end of year-1.
0570             if year > 1:
0571                 d = self.theclass.fromordinal(n-1)
0572                 d2 = self.theclass(year-1, 12, 31)
0573                 self.assertEqual(d, d2)
0574                 self.assertEqual(d2.toordinal(), n-1)
0575 
0576         # Test every day in a leap-year and a non-leap year.
0577         dim = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
0578         for year, isleap in (2000, True), (2002, False):
0579             n = self.theclass(year, 1, 1).toordinal()
0580             for month, maxday in zip(range(1, 13), dim):
0581                 if month == 2 and isleap:
0582                     maxday += 1
0583                 for day in range(1, maxday+1):
0584                     d = self.theclass(year, month, day)
0585                     self.assertEqual(d.toordinal(), n)
0586                     self.assertEqual(d, self.theclass.fromordinal(n))
0587                     n += 1
0588 
0589     def test_extreme_ordinals(self):
0590         a = self.theclass.min
0591         a = self.theclass(a.year, a.month, a.day)  # get rid of time parts
0592         aord = a.toordinal()
0593         b = a.fromordinal(aord)
0594         self.assertEqual(a, b)
0595 
0596         self.assertRaises(ValueError, lambda: a.fromordinal(aord - 1))
0597 
0598         b = a + timedelta(days=1)
0599         self.assertEqual(b.toordinal(), aord + 1)
0600         self.assertEqual(b, self.theclass.fromordinal(aord + 1))
0601 
0602         a = self.theclass.max
0603         a = self.theclass(a.year, a.month, a.day)  # get rid of time parts
0604         aord = a.toordinal()
0605         b = a.fromordinal(aord)
0606         self.assertEqual(a, b)
0607 
0608         self.assertRaises(ValueError, lambda: a.fromordinal(aord + 1))
0609 
0610         b = a - timedelta(days=1)
0611         self.assertEqual(b.toordinal(), aord - 1)
0612         self.assertEqual(b, self.theclass.fromordinal(aord - 1))
0613 
0614     def test_bad_constructor_arguments(self):
0615         # bad years
0616         self.theclass(MINYEAR, 1, 1)  # no exception
0617         self.theclass(MAXYEAR, 1, 1)  # no exception
0618         self.assertRaises(ValueError, self.theclass, MINYEAR-1, 1, 1)
0619         self.assertRaises(ValueError, self.theclass, MAXYEAR+1, 1, 1)
0620         # bad months
0621         self.theclass(2000, 1, 1)    # no exception
0622         self.theclass(2000, 12, 1)   # no exception
0623         self.assertRaises(ValueError, self.theclass, 2000, 0, 1)
0624         self.assertRaises(ValueError, self.theclass, 2000, 13, 1)
0625         # bad days
0626         self.theclass(2000, 2, 29)   # no exception
0627         self.theclass(2004, 2, 29)   # no exception
0628         self.theclass(2400, 2, 29)   # no exception
0629         self.assertRaises(ValueError, self.theclass, 2000, 2, 30)
0630         self.assertRaises(ValueError, self.theclass, 2001, 2, 29)
0631         self.assertRaises(ValueError, self.theclass, 2100, 2, 29)
0632         self.assertRaises(ValueError, self.theclass, 1900, 2, 29)
0633         self.assertRaises(ValueError, self.theclass, 2000, 1, 0)
0634         self.assertRaises(ValueError, self.theclass, 2000, 1, 32)
0635 
0636     def test_hash_equality(self):
0637         d = self.theclass(2000, 12, 31)
0638         # same thing
0639         e = self.theclass(2000, 12, 31)
0640         self.assertEqual(d, e)
0641         self.assertEqual(hash(d), hash(e))
0642 
0643         dic = {d: 1}
0644         dic[e] = 2
0645         self.assertEqual(len(dic), 1)
0646         self.assertEqual(dic[d], 2)
0647         self.assertEqual(dic[e], 2)
0648 
0649         d = self.theclass(2001,  1,  1)
0650         # same thing
0651         e = self.theclass(2001,  1,  1)
0652         self.assertEqual(d, e)
0653         self.assertEqual(hash(d), hash(e))
0654 
0655         dic = {d: 1}
0656         dic[e] = 2
0657         self.assertEqual(len(dic), 1)
0658         self.assertEqual(dic[d], 2)
0659         self.assertEqual(dic[e], 2)
0660 
0661     def test_computations(self):
0662         a = self.theclass(2002, 1, 31)
0663         b = self.theclass(1956, 1, 31)
0664 
0665         diff = a-b
0666         self.assertEqual(diff.days, 46*365 + len(range(1956, 2002, 4)))
0667         self.assertEqual(diff.seconds, 0)
0668         self.assertEqual(diff.microseconds, 0)
0669 
0670         day = timedelta(1)
0671         week = timedelta(7)
0672         a = self.theclass(2002, 3, 2)
0673         self.assertEqual(a + day, self.theclass(2002, 3, 3))
0674         self.assertEqual(day + a, self.theclass(2002, 3, 3))
0675         self.assertEqual(a - day, self.theclass(2002, 3, 1))
0676         self.assertEqual(-day + a, self.theclass(2002, 3, 1))
0677         self.assertEqual(a + week, self.theclass(2002, 3, 9))
0678         self.assertEqual(a - week, self.theclass(2002, 2, 23))
0679         self.assertEqual(a + 52*week, self.theclass(2003, 3, 1))
0680         self.assertEqual(a - 52*week, self.theclass(2001, 3, 3))
0681         self.assertEqual((a + week) - a, week)
0682         self.assertEqual((a + day) - a, day)
0683         self.assertEqual((a - week) - a, -week)
0684         self.assertEqual((a - day) - a, -day)
0685         self.assertEqual(a - (a + week), -week)
0686         self.assertEqual(a - (a + day), -day)
0687         self.assertEqual(a - (a - week), week)
0688         self.assertEqual(a - (a - day), day)
0689 
0690         # Add/sub ints, longs, floats should be illegal
0691         for i in 1, 1L, 1.0:
0692             self.assertRaises(TypeError, lambda: a+i)
0693             self.assertRaises(TypeError, lambda: a-i)
0694             self.assertRaises(TypeError, lambda: i+a)
0695             self.assertRaises(TypeError, lambda: i-a)
0696 
0697         # delta - date is senseless.
0698         self.assertRaises(TypeError, lambda: day - a)
0699         # mixing date and (delta or date) via * or // is senseless
0700         self.assertRaises(TypeError, lambda: day * a)
0701         self.assertRaises(TypeError, lambda: a * day)
0702         self.assertRaises(TypeError, lambda: day // a)
0703         self.assertRaises(TypeError, lambda: a // day)
0704         self.assertRaises(TypeError, lambda: a * a)
0705         self.assertRaises(TypeError, lambda: a // a)
0706         # date + date is senseless
0707         self.assertRaises(TypeError, lambda: a + a)
0708 
0709     def test_overflow(self):
0710         tiny = self.theclass.resolution
0711 
0712         dt = self.theclass.min + tiny
0713         dt -= tiny  # no problem
0714         self.assertRaises(OverflowError, dt.__sub__, tiny)
0715         self.assertRaises(OverflowError, dt.__add__, -tiny)
0716 
0717         dt = self.theclass.max - tiny
0718         dt += tiny  # no problem
0719         self.assertRaises(OverflowError, dt.__add__, tiny)
0720         self.assertRaises(OverflowError, dt.__sub__, -tiny)
0721 
0722     def test_fromtimestamp(self):
0723         import time
0724 
0725         # Try an arbitrary fixed value.
0726         year, month, day = 1999, 9, 19
0727         ts = time.mktime((year, month, day, 0, 0, 0, 0, 0, -1))
0728         d = self.theclass.fromtimestamp(ts)
0729         self.assertEqual(d.year, year)
0730         self.assertEqual(d.month, month)
0731         self.assertEqual(d.day, day)
0732 
0733     def test_insane_fromtimestamp(self):
0734         # It's possible that some platform maps time_t to double,
0735         # and that this test will fail there.  This test should
0736         # exempt such platforms (provided they return reasonable
0737         # results!).
0738         for insane in -1e200, 1e200:
0739             self.assertRaises(ValueError, self.theclass.fromtimestamp,
0740                               insane)
0741 
0742     def test_today(self):
0743         import time
0744 
0745         # We claim that today() is like fromtimestamp(time.time()), so
0746         # prove it.
0747         for dummy in range(3):
0748             today = self.theclass.today()
0749             ts = time.time()
0750             todayagain = self.theclass.fromtimestamp(ts)
0751             if today == todayagain:
0752                 break
0753             # There are several legit reasons that could fail:
0754             # 1. It recently became midnight, between the today() and the
0755             #    time() calls.
0756             # 2. The platform time() has such fine resolution that we'll
0757             #    never get the same value twice.
0758             # 3. The platform time() has poor resolution, and we just
0759             #    happened to call today() right before a resolution quantum
0760             #    boundary.
0761             # 4. The system clock got fiddled between calls.
0762             # In any case, wait a little while and try again.
0763             time.sleep(0.1)
0764 
0765         # It worked or it didn't.  If it didn't, assume it's reason #2, and
0766         # let the test pass if they're within half a second of each other.
0767         self.failUnless(today == todayagain or
0768                         abs(todayagain - today) < timedelta(seconds=0.5))
0769 
0770     def test_weekday(self):
0771         for i in range(7):
0772             # March 4, 2002 is a Monday
0773             self.assertEqual(self.theclass(2002, 3, 4+i).weekday(), i)
0774             self.assertEqual(self.theclass(2002, 3, 4+i).isoweekday(), i+1)
0775             # January 2, 1956 is a Monday
0776             self.assertEqual(self.theclass(1956, 1, 2+i).weekday(), i)
0777             self.assertEqual(self.theclass(1956, 1, 2+i).isoweekday(), i+1)
0778 
0779     def test_isocalendar(self):
0780         # Check examples from
0781         # http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
0782         for i in range(7):
0783             d = self.theclass(2003, 12, 22+i)
0784             self.assertEqual(d.isocalendar(), (2003, 52, i+1))
0785             d = self.theclass(2003, 12, 29) + timedelta(i)
0786             self.assertEqual(d.isocalendar(), (2004, 1, i+1))
0787             d = self.theclass(2004, 1, 5+i)
0788             self.assertEqual(d.isocalendar(), (2004, 2, i+1))
0789             d = self.theclass(2009, 12, 21+i)
0790             self.assertEqual(d.isocalendar(), (2009, 52, i+1))
0791             d = self.theclass(2009, 12, 28) + timedelta(i)
0792             self.assertEqual(d.isocalendar(), (2009, 53, i+1))
0793             d = self.theclass(2010, 1, 4+i)
0794             self.assertEqual(d.isocalendar(), (2010, 1, i+1))
0795 
0796     def test_iso_long_years(self):
0797         # Calculate long ISO years and compare to table from
0798         # http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
0799         ISO_LONG_YEARS_TABLE = """
0800               4   32   60   88
0801               9   37   65   93
0802              15   43   71   99
0803              20   48   76
0804              26   54   82
0805 
0806             105  133  161  189
0807             111  139  167  195
0808             116  144  172
0809             122  150  178
0810             128  156  184
0811 
0812             201  229  257  285
0813             207  235  263  291
0814             212  240  268  296
0815             218  246  274
0816             224  252  280
0817 
0818             303  331  359  387
0819             308  336  364  392
0820             314  342  370  398
0821             320  348  376
0822             325  353  381
0823         """
0824         iso_long_years = map(int, ISO_LONG_YEARS_TABLE.split())
0825         iso_long_years.sort()
0826         L = []
0827         for i in range(400):
0828             d = self.theclass(2000+i, 12, 31)
0829             d1 = self.theclass(1600+i, 12, 31)
0830             self.assertEqual(d.isocalendar()[1:], d1.isocalendar()[1:])
0831             if d.isocalendar()[1] == 53:
0832                 L.append(i)
0833         self.assertEqual(L, iso_long_years)
0834 
0835     def test_isoformat(self):
0836         t = self.theclass(2, 3, 2)
0837         self.assertEqual(t.isoformat(), "0002-03-02")
0838 
0839     def test_ctime(self):
0840         t = self.theclass(2002, 3, 2)
0841         self.assertEqual(t.ctime(), "Sat Mar  2 00:00:00 2002")
0842 
0843     def test_strftime(self):
0844         t = self.theclass(2005, 3, 2)
0845         self.assertEqual(t.strftime("m:%m d:%d y:%y"), "m:03 d:02 y:05")
0846         self.assertEqual(t.strftime(""), "") # SF bug #761337
0847 
0848         self.assertRaises(TypeError, t.strftime) # needs an arg
0849         self.assertRaises(TypeError, t.strftime, "one", "two") # too many args
0850         self.assertRaises(TypeError, t.strftime, 42) # arg wrong type
0851 
0852         # A naive object replaces %z and %Z w/ empty strings.
0853         self.assertEqual(t.strftime("'%z' '%Z'"), "'' ''")
0854 
0855     def test_resolution_info(self):
0856         self.assert_(isinstance(self.theclass.min, self.theclass))
0857         self.assert_(isinstance(self.theclass.max, self.theclass))
0858         self.assert_(isinstance(self.theclass.resolution, timedelta))
0859         self.assert_(self.theclass.max > self.theclass.min)
0860 
0861     def test_extreme_timedelta(self):
0862         big = self.theclass.max - self.theclass.min
0863         # 3652058 days, 23 hours, 59 minutes, 59 seconds, 999999 microseconds
0864         n = (big.days*24*3600 + big.seconds)*1000000 + big.microseconds
0865         # n == 315537897599999999 ~= 2**58.13
0866         justasbig = timedelta(0, 0, n)
0867         self.assertEqual(big, justasbig)
0868         self.assertEqual(self.theclass.min + big, self.theclass.max)
0869         self.assertEqual(self.theclass.max - big, self.theclass.min)
0870 
0871     def test_timetuple(self):
0872         for i in range(7):
0873             # January 2, 1956 is a Monday (0)
0874             d = self.theclass(1956, 1, 2+i)
0875             t = d.timetuple()
0876             self.assertEqual(t, (1956, 1, 2+i, 0, 0, 0, i, 2+i, -1))
0877             # February 1, 1956 is a Wednesday (2)
0878             d = self.theclass(1956, 2, 1+i)
0879             t = d.timetuple()
0880             self.assertEqual(t, (1956, 2, 1+i, 0, 0, 0, (2+i)%7, 32+i, -1))
0881             # March 1, 1956 is a Thursday (3), and is the 31+29+1 = 61st day
0882             # of the year.
0883             d = self.theclass(1956, 3, 1+i)
0884             t = d.timetuple()
0885             self.assertEqual(t, (1956, 3, 1+i, 0, 0, 0, (3+i)%7, 61+i, -1))
0886             self.assertEqual(t.tm_year, 1956)
0887             self.assertEqual(t.tm_mon, 3)
0888             self.assertEqual(t.tm_mday, 1+i)
0889             self.assertEqual(t.tm_hour, 0)
0890             self.assertEqual(t.tm_min, 0)
0891             self.assertEqual(t.tm_sec, 0)
0892             self.assertEqual(t.tm_wday, (3+i)%7)
0893             self.assertEqual(t.tm_yday, 61+i)
0894             self.assertEqual(t.tm_isdst, -1)
0895 
0896     def test_pickling(self):
0897         args = 6, 7, 23
0898         orig = self.theclass(*args)
0899         for pickler, unpickler, proto in pickle_choices:
0900             green = pickler.dumps(orig, proto)
0901             derived = unpickler.loads(green)
0902             self.assertEqual(orig, derived)
0903 
0904     def test_compare(self):
0905         t1 = self.theclass(2, 3, 4)
0906         t2 = self.theclass(2, 3, 4)
0907         self.failUnless(t1 == t2)
0908         self.failUnless(t1 <= t2)
0909         self.failUnless(t1 >= t2)
0910         self.failUnless(not t1 != t2)
0911         self.failUnless(not t1 < t2)
0912         self.failUnless(not t1 > t2)
0913         self.assertEqual(cmp(t1, t2), 0)
0914         self.assertEqual(cmp(t2, t1), 0)
0915 
0916         for args in (3, 3, 3), (2, 4, 4), (2, 3, 5):
0917             t2 = self.theclass(*args)   # this is larger than t1
0918             self.failUnless(t1 < t2)
0919             self.failUnless(t2 > t1)
0920             self.failUnless(t1 <= t2)
0921             self.failUnless(t2 >= t1)
0922             self.failUnless(t1 != t2)
0923             self.failUnless(t2 != t1)
0924             self.failUnless(not t1 == t2)
0925             self.failUnless(not t2 == t1)
0926             self.failUnless(not t1 > t2)
0927             self.failUnless(not t2 < t1)
0928             self.failUnless(not t1 >= t2)
0929             self.failUnless(not t2 <= t1)
0930             self.assertEqual(cmp(t1, t2), -1)
0931             self.assertEqual(cmp(t2, t1), 1)
0932 
0933         for badarg in OTHERSTUFF:
0934             self.assertEqual(t1 == badarg, False)
0935             self.assertEqual(t1 != badarg, True)
0936             self.assertEqual(badarg == t1, False)
0937             self.assertEqual(badarg != t1, True)
0938 
0939             self.assertRaises(TypeError, lambda: t1 < badarg)
0940             self.assertRaises(TypeError, lambda: t1 > badarg)
0941             self.assertRaises(TypeError, lambda: t1 >= badarg)
0942             self.assertRaises(TypeError, lambda: badarg <= t1)
0943             self.assertRaises(TypeError, lambda: badarg < t1)
0944             self.assertRaises(TypeError, lambda: badarg > t1)
0945             self.assertRaises(TypeError, lambda: badarg >= t1)
0946 
0947     def test_mixed_compare(self):
0948         our = self.theclass(2000, 4, 5)
0949         self.assertRaises(TypeError, cmp, our, 1)
0950         self.assertRaises(TypeError, cmp, 1, our)
0951 
0952         class AnotherDateTimeClass(object):
0953             def __cmp__(self, other):
0954                 # Return "equal" so calling this can't be confused with
0955                 # compare-by-address (which never says "equal" for distinct
0956                 # objects).
0957                 return 0
0958 
0959         # This still errors, because date and datetime comparison raise
0960         # TypeError instead of NotImplemented when they don't know what to
0961         # do, in order to stop comparison from falling back to the default
0962         # compare-by-address.
0963         their = AnotherDateTimeClass()
0964         self.assertRaises(TypeError, cmp, our, their)
0965         # Oops:  The next stab raises TypeError in the C implementation,
0966         # but not in the Python implementation of datetime.  The difference
0967         # is due to that the Python implementation defines __cmp__ but
0968         # the C implementation defines tp_richcompare.  This is more pain
0969         # to fix than it's worth, so commenting out the test.
0970         # self.assertEqual(cmp(their, our), 0)
0971 
0972         # But date and datetime comparison return NotImplemented instead if the
0973         # other object has a timetuple attr.  This gives the other object a
0974         # chance to do the comparison.
0975         class Comparable(AnotherDateTimeClass):
0976             def timetuple(self):
0977                 return ()
0978 
0979         their = Comparable()
0980         self.assertEqual(cmp(our, their), 0)
0981         self.assertEqual(cmp(their, our), 0)
0982         self.failUnless(our == their)
0983         self.failUnless(their == our)
0984 
0985     def test_bool(self):
0986         # All dates are considered true.
0987         self.failUnless(self.theclass.min)
0988         self.failUnless(self.theclass.max)
0989 
0990     def test_srftime_out_of_range(self):
0991         # For nasty technical reasons, we can't handle years before 1900.
0992         cls = self.theclass
0993         self.assertEqual(cls(1900, 1, 1).strftime("%Y"), "1900")
0994         for y in 1, 49, 51, 99, 100, 1000, 1899:
0995             self.assertRaises(ValueError, cls(y, 1, 1).strftime, "%Y")
0996 
0997     def test_replace(self):
0998         cls = self.theclass
0999         args = [1, 2, 3]
1000         base = cls(*args)
1001         self.assertEqual(base, base.replace())
1002 
1003         i = 0
1004         for name, newval in (("year", 2),
1005                              ("month", 3),
1006                              ("day", 4)):
1007             newargs = args[:]
1008             newargs[i] = newval
1009             expected = cls(*newargs)
1010             got = base.replace(**{name: newval})
1011             self.assertEqual(expected, got)
1012             i += 1
1013 
1014         # Out of bounds.
1015         base = cls(2000, 2, 29)
1016         self.assertRaises(ValueError, base.replace, year=2001)
1017 
1018     def test_subclass_date(self):
1019 
1020         class C(self.theclass):
1021             theAnswer = 42
1022 
1023             def __new__(cls, *args, **kws):
1024                 temp = kws.copy()
1025                 extra = temp.pop('extra')
1026                 result = self.theclass.__new__(cls, *args, **temp)
1027                 result.extra = extra
1028                 return result
1029 
1030             def newmeth(self, start):
1031                 return start + self.year + self.month
1032 
1033         args = 2003, 4, 14
1034 
1035         dt1 = self.theclass(*args)
1036         dt2 = C(*args, **{'extra': 7})
1037 
1038         self.assertEqual(dt2.__class__, C)
1039         self.assertEqual(dt2.theAnswer, 42)
1040         self.assertEqual(dt2.extra, 7)
1041         self.assertEqual(dt1.toordinal(), dt2.toordinal())
1042         self.assertEqual(dt2.newmeth(-7), dt1.year + dt1.month - 7)
1043 
1044     def test_pickling_subclass_date(self):
1045 
1046         args = 6, 7, 23
1047         orig = SubclassDate(*args)
1048         for pickler, unpickler, proto in pickle_choices:
1049             green = pickler.dumps(orig, proto)
1050             derived = unpickler.loads(green)
1051             self.assertEqual(orig, derived)
1052 
1053     def test_backdoor_resistance(self):
1054         # For fast unpickling, the constructor accepts a pickle string.
1055         # This is a low-overhead backdoor.  A user can (by intent or
1056         # mistake) pass a string directly, which (if it's the right length)
1057         # will get treated like a pickle, and bypass the normal sanity
1058         # checks in the constructor.  This can create insane objects.
1059         # The constructor doesn't want to burn the time to validate all
1060         # fields, but does check the month field.  This stops, e.g.,
1061         # datetime.datetime('1995-03-25') from yielding an insane object.
1062         base = '1995-03-25'
1063         if not issubclass(self.theclass, datetime):
1064             base = base[:4]
1065         for month_byte in '9', chr(0), chr(13), '\xff':
1066             self.assertRaises(TypeError, self.theclass,
1067                                          base[:2] + month_byte + base[3:])
1068         for ord_byte in range(1, 13):
1069             # This shouldn't blow up because of the month byte alone.  If
1070             # the implementation changes to do more-careful checking, it may
1071             # blow up because other fields are insane.
1072             self.theclass(base[:2] + chr(ord_byte) + base[3:])
1073 
1074 #############################################################################
1075 # datetime tests
1076 
1077 class SubclassDatetime(datetime):
1078     sub_var = 1
1079 
1080 class TestDateTime(TestDate):
1081 
1082     theclass = datetime
1083 
1084     def test_basic_attributes(self):
1085         dt = self.theclass(2002, 3, 1, 12, 0)
1086         self.assertEqual(dt.year, 2002)
1087         self.assertEqual(dt.month, 3)
1088         self.assertEqual(dt.day, 1)
1089         self.assertEqual(dt.hour, 12)
1090         self.assertEqual(dt.minute, 0)
1091         self.assertEqual(dt.second, 0)
1092         self.assertEqual(dt.microsecond, 0)
1093 
1094     def test_basic_attributes_nonzero(self):
1095         # Make sure all attributes are non-zero so bugs in
1096         # bit-shifting access show up.
1097         dt = self.theclass(2002, 3, 1, 12, 59, 59, 8000)
1098         self.assertEqual(dt.year, 2002)
1099         self.assertEqual(dt.month, 3)
1100         self.assertEqual(dt.day, 1)
1101         self.assertEqual(dt.hour, 12)
1102         self.assertEqual(dt.minute, 59)
1103         self.assertEqual(dt.second, 59)
1104         self.assertEqual(dt.microsecond, 8000)
1105 
1106     def test_roundtrip(self):
1107         for dt in (self.theclass(1, 2, 3, 4, 5, 6, 7),
1108                    self.theclass.now()):
1109             # Verify dt -> string -> datetime identity.
1110             s = repr(dt)
1111             self.failUnless(s.startswith('datetime.'))
1112             s = s[9:]
1113             dt2 = eval(s)
1114             self.assertEqual(dt, dt2)
1115 
1116             # Verify identity via reconstructing from pieces.
1117             dt2 = self.theclass(dt.year, dt.month, dt.day,
1118                                 dt.hour, dt.minute, dt.second,
1119                                 dt.microsecond)
1120             self.assertEqual(dt, dt2)
1121 
1122     def test_isoformat(self):
1123         t = self.theclass(2, 3, 2, 4, 5, 1, 123)
1124         self.assertEqual(t.isoformat(),    "0002-03-02T04:05:01.000123")
1125         self.assertEqual(t.isoformat('T'), "0002-03-02T04:05:01.000123")
1126         self.assertEqual(t.isoformat(' '), "0002-03-02 04:05:01.000123")
1127         # str is ISO format with the separator forced to a blank.
1128         self.assertEqual(str(t), "0002-03-02 04:05:01.000123")
1129 
1130         t = self.theclass(2, 3, 2)
1131         self.assertEqual(t.isoformat(),    "0002-03-02T00:00:00")
1132         self.assertEqual(t.isoformat('T'), "0002-03-02T00:00:00")
1133         self.assertEqual(t.isoformat(' '), "0002-03-02 00:00:00")
1134         # str is ISO format with the separator forced to a blank.
1135         self.assertEqual(str(t), "0002-03-02 00:00:00")
1136 
1137     def test_more_ctime(self):
1138         # Test fields that TestDate doesn't touch.
1139         import time
1140 
1141         t = self.theclass(2002, 3, 2, 18, 3, 5, 123)
1142         self.assertEqual(t.ctime(), "Sat Mar  2 18:03:05 2002")
1143         # Oops!  The next line fails on Win2K under MSVC 6, so it's commented
1144         # out.  The difference is that t.ctime() produces " 2" for the day,
1145         # but platform ctime() produces "02" for the day.  According to
1146         # C99, t.ctime() is correct here.
1147         # self.assertEqual(t.ctime(), time.ctime(time.mktime(t.timetuple())))
1148 
1149         # So test a case where that difference doesn't matter.
1150         t = self.theclass(2002, 3, 22, 18, 3, 5, 123)
1151         self.assertEqual(t.ctime(), time.ctime(time.mktime(t.timetuple())))
1152 
1153     def test_tz_independent_comparing(self):
1154         dt1 = self.theclass(2002, 3, 1, 9, 0, 0)
1155         dt2 = self.theclass(2002, 3, 1, 10, 0, 0)
1156         dt3 = self.theclass(2002, 3, 1, 9, 0, 0)
1157         self.assertEqual(dt1, dt3)
1158         self.assert_(dt2 > dt3)
1159 
1160         # Make sure comparison doesn't forget microseconds, and isn't done
1161         # via comparing a float timestamp (an IEEE double doesn't have enough
1162         # precision to span microsecond resolution across years 1 thru 9999,
1163         # so comparing via timestamp necessarily calls some distinct values
1164         # equal).
1165         dt1 = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999998)
1166         us = timedelta(microseconds=1)
1167         dt2 = dt1 + us
1168         self.assertEqual(dt2 - dt1, us)
1169         self.assert_(dt1 < dt2)
1170 
1171     def test_bad_constructor_arguments(self):
1172         # bad years
1173         self.theclass(MINYEAR, 1, 1)  # no exception
1174         self.theclass(MAXYEAR, 1, 1)  # no exception
1175         self.assertRaises(ValueError, self.theclass, MINYEAR-1, 1, 1)
1176         self.assertRaises(ValueError, self.theclass, MAXYEAR+1, 1, 1)
1177         # bad months
1178         self.theclass(2000, 1, 1)    # no exception
1179         self.theclass(2000, 12, 1)   # no exception
1180         self.assertRaises(ValueError, self.theclass, 2000, 0, 1)
1181         self.assertRaises(ValueError, self.theclass, 2000, 13, 1)
1182         # bad days
1183         self.theclass(2000, 2, 29)   # no exception
1184         self.theclass(2004, 2, 29)   # no exception
1185         self.theclass(2400, 2, 29)   # no exception
1186         self.assertRaises(ValueError, self.theclass, 2000, 2, 30)
1187         self.assertRaises(ValueError, self.theclass, 2001, 2, 29)
1188         self.assertRaises(ValueError, self.theclass, 2100, 2, 29)
1189         self.assertRaises(ValueError, self.theclass, 1900, 2, 29)
1190         self.assertRaises(ValueError, self.theclass, 2000, 1, 0)
1191         self.assertRaises(ValueError, self.theclass, 2000, 1, 32)
1192         # bad hours
1193         self.theclass(2000, 1, 31, 0)    # no exception
1194         self.theclass(2000, 1, 31, 23)   # no exception
1195         self.assertRaises(ValueError, self.theclass, 2000, 1, 31, -1)
1196         self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 24)
1197         # bad minutes
1198         self.theclass(2000, 1, 31, 23, 0)    # no exception
1199         self.theclass(2000, 1, 31, 23, 59)   # no exception
1200         self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 23, -1)
1201         self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 23, 60)
1202         # bad seconds
1203         self.theclass(2000, 1, 31, 23, 59, 0)    # no exception
1204         self.theclass(2000, 1, 31, 23, 59, 59)   # no exception
1205         self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 23, 59, -1)
1206         self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 23, 59, 60)
1207         # bad microseconds
1208         self.theclass(2000, 1, 31, 23, 59, 59, 0)    # no exception
1209         self.theclass(2000, 1, 31, 23, 59, 59, 999999)   # no exception
1210         self.assertRaises(ValueError, self.theclass,
1211                           2000, 1, 31, 23, 59, 59, -1)
1212         self.assertRaises(ValueError, self.theclass,
1213                           2000, 1, 31, 23, 59, 59,
1214                           1000000)
1215 
1216     def test_hash_equality(self):
1217         d = self.theclass(2000, 12, 31, 23, 30, 17)
1218         e = self.theclass(2000, 12, 31, 23, 30, 17)
1219         self.assertEqual(d, e)
1220         self.assertEqual(hash(d), hash(e))
1221 
1222         dic = {d: 1}
1223         dic[e] = 2
1224         self.assertEqual(len(dic), 1)
1225         self.assertEqual(dic[d], 2)
1226         self.assertEqual(dic[e], 2)
1227 
1228         d = self.theclass(2001,  1,  1,  0,  5, 17)
1229         e = self.theclass(2001,  1,  1,  0,  5, 17)
1230         self.assertEqual(d, e)
1231         self.assertEqual(hash(d), hash(e))
1232 
1233         dic = {d: 1}
1234         dic[e] = 2
1235         self.assertEqual(len(dic), 1)
1236         self.assertEqual(dic[d], 2)
1237         self.assertEqual(dic[e], 2)
1238 
1239     def test_computations(self):
1240         a = self.theclass(2002, 1, 31)
1241         b = self.theclass(1956, 1, 31)
1242         diff = a-b
1243         self.assertEqual(diff.days, 46*365 + len(range(1956, 2002, 4)))
1244         self.assertEqual(diff.seconds, 0)
1245         self.assertEqual(diff.microseconds, 0)
1246         a = self.theclass(2002, 3, 2, 17, 6)
1247         millisec = timedelta(0, 0, 1000)
1248         hour = timedelta(0, 3600)
1249         day = timedelta(1)
1250         week = timedelta(7)
1251         self.assertEqual(a + hour, self.theclass(2002, 3, 2, 18, 6))
1252         self.assertEqual(hour + a, self.theclass(2002, 3, 2, 18, 6))
1253         self.assertEqual(a + 10*hour, self.theclass(2002, 3, 3, 3, 6))
1254         self.assertEqual(a - hour, self.theclass(2002, 3, 2, 16, 6))
1255         self.assertEqual(-hour + a, self.theclass(2002, 3, 2, 16, 6))
1256         self.assertEqual(a - hour, a + -hour)
1257         self.assertEqual(a - 20*hour, self.theclass(2002, 3, 1, 21, 6))
1258         self.assertEqual(a + day, self.theclass(2002, 3, 3, 17, 6))
1259         self.assertEqual(a - day, self.theclass(2002, 3, 1, 17, 6))
1260         self.assertEqual(a + week, self.theclass(2002, 3, 9, 17, 6))
1261         self.assertEqual(a - week, self.theclass(2002, 2, 23, 17, 6))
1262         self.assertEqual(a + 52*week, self.theclass(2003, 3, 1, 17, 6))
1263         self.assertEqual(a - 52*week, self.theclass(2001, 3, 3, 17, 6))
1264         self.assertEqual((a + week) - a, week)
1265         self.assertEqual((a + day) - a, day)
1266         self.assertEqual((a + hour) - a, hour)
1267         self.assertEqual((a + millisec) - a, millisec)
1268         self.assertEqual((a - week) - a, -week)
1269         self.assertEqual((a - day) - a, -day)
1270         self.assertEqual((a - hour) - a, -hour)
1271         self.assertEqual((a - millisec) - a, -millisec)
1272         self.assertEqual(a - (a + week), -week)
1273         self.assertEqual(a - (a + day), -day)
1274         self.assertEqual(a - (a + hour), -hour)
1275         self.assertEqual(a - (a + millisec), -millisec)
1276         self.assertEqual(a - (a - week), week)
1277         self.assertEqual(a - (a - day), day)
1278         self.assertEqual(a - (a - hour), hour)
1279         self.assertEqual(a - (a - millisec), millisec)
1280         self.assertEqual(a + (week + day + hour + millisec),
1281                          self.theclass(2002, 3, 10, 18, 6, 0, 1000))
1282         self.assertEqual(a + (week + day + hour + millisec),
1283                          (((a + week) + day) + hour) + millisec)
1284         self.assertEqual(a - (week + day + hour + millisec),
1285                          self.theclass(2002, 2, 22, 16, 5, 59, 999000))
1286         self.assertEqual(a - (week + day + hour + millisec),
1287                          (((a - week) - day) - hour) - millisec)
1288         # Add/sub ints, longs, floats should be illegal
1289         for i in 1, 1L, 1.0:
1290             self.assertRaises(TypeError, lambda: a+i)
1291             self.assertRaises(TypeError, lambda: a-i)
1292             self.assertRaises(TypeError, lambda: i+a)
1293             self.assertRaises(TypeError, lambda: i-a)
1294 
1295         # delta - datetime is senseless.
1296         self.assertRaises(TypeError, lambda: day - a)
1297         # mixing datetime and (delta or datetime) via * or // is senseless
1298         self.assertRaises(TypeError, lambda: day * a)
1299         self.assertRaises(TypeError, lambda: a * day)
1300         self.assertRaises(TypeError, lambda: day // a)
1301         self.assertRaises(TypeError, lambda: a // day)
1302         self.assertRaises(TypeError, lambda: a * a)
1303         self.assertRaises(TypeError, lambda: a // a)
1304         # datetime + datetime is senseless
1305         self.assertRaises(TypeError, lambda: a + a)
1306 
1307     def test_pickling(self):
1308         args = 6, 7, 23, 20, 59, 1, 64**2
1309         orig = self.theclass(*args)
1310         for pickler, unpickler, proto in pickle_choices:
1311             green = pickler.dumps(orig, proto)
1312             derived = unpickler.loads(green)
1313             self.assertEqual(orig, derived)
1314 
1315     def test_more_pickling(self):
1316         a = self.theclass(2003, 2, 7, 16, 48, 37, 444116)
1317         s = pickle.dumps(a)
1318         b = pickle.loads(s)
1319         self.assertEqual(b.year, 2003)
1320         self.assertEqual(b.month, 2)
1321         self.assertEqual(b.day, 7)
1322 
1323     def test_pickling_subclass_datetime(self):
1324         args = 6, 7, 23, 20, 59, 1, 64**2
1325         orig = SubclassDatetime(*args)
1326         for pickler, unpickler, proto in pickle_choices:
1327             green = pickler.dumps(orig, proto)
1328             derived = unpickler.loads(green)
1329             self.assertEqual(orig, derived)
1330 
1331     def test_more_compare(self):
1332         # The test_compare() inherited from TestDate covers the error cases.
1333         # We just want to test lexicographic ordering on the members datetime
1334         # has that date lacks.
1335         args = [2000, 11, 29, 20, 58, 16, 999998]
1336         t1 = self.theclass(*args)
1337         t2 = self.theclass(*args)
1338         self.failUnless(t1 == t2)
1339         self.failUnless(t1 <= t2)
1340         self.failUnless(t1 >= t2)
1341         self.failUnless(not t1 != t2)
1342         self.failUnless(not t1 < t2)
1343         self.failUnless(not t1 > t2)
1344         self.assertEqual(cmp(t1, t2), 0)
1345         self.assertEqual(cmp(t2, t1), 0)
1346 
1347         for i in range(len(args)):
1348             newargs = args[:]
1349             newargs[i] = args[i] + 1
1350             t2 = self.theclass(*newargs)   # this is larger than t1
1351             self.failUnless(t1 < t2)
1352             self.failUnless(t2 > t1)
1353             self.failUnless(t1 <= t2)
1354             self.failUnless(t2 >= t1)
1355             self.failUnless(t1 != t2)
1356             self.failUnless(t2 != t1)
1357             self.failUnless(not t1 == t2)
1358             self.failUnless(not t2 == t1)
1359             self.failUnless(not t1 > t2)
1360             self.failUnless(not t2 < t1)
1361             self.failUnless(not t1 >= t2)
1362             self.failUnless(not t2 <= t1)
1363             self.assertEqual(cmp(t1, t2), -1)
1364             self.assertEqual(cmp(t2, t1), 1)
1365 
1366 
1367     # A helper for timestamp constructor tests.
1368     def verify_field_equality(self, expected, got):
1369         self.assertEqual(expected.tm_year, got.year)
1370         self.assertEqual(expected.tm_mon, got.month)
1371         self.assertEqual(expected.tm_mday, got.day)
1372         self.assertEqual(expected.tm_hour, got.hour)
1373         self.assertEqual(expected.tm_min, got.minute)
1374         self.assertEqual(expected.tm_sec, got.second)
1375 
1376     def test_fromtimestamp(self):
1377         import time
1378 
1379         ts = time.time()
1380         expected = time.localtime(ts)
1381         got = self.theclass.fromtimestamp(ts)
1382         self.verify_field_equality(expected, got)
1383 
1384     def test_utcfromtimestamp(self):
1385         import time
1386 
1387         ts = time.time()
1388         expected = time.gmtime(ts)
1389         got = self.theclass.utcfromtimestamp(ts)
1390         self.verify_field_equality(expected, got)
1391 
1392     def test_insane_fromtimestamp(self):
1393         # It's possible that some platform maps time_t to double,
1394         # and that this test will fail there.  This test should
1395         # exempt such platforms (provided they return reasonable
1396         # results!).
1397         for insane in -1e200, 1e200:
1398             self.assertRaises(ValueError, self.theclass.fromtimestamp,
1399                               insane)
1400 
1401     def test_insane_utcfromtimestamp(self):
1402         # It's possible that some platform maps time_t to double,
1403         # and that this test will fail there.  This test should
1404         # exempt such platforms (provided they return reasonable
1405         # results!).
1406         for insane in -1e200, 1e200:
1407             self.assertRaises(ValueError, self.theclass.utcfromtimestamp,
1408                               insane)
1409 
1410     def test_utcnow(self):
1411         import time
1412 
1413         # Call it a success if utcnow() and utcfromtimestamp() are within
1414         # a second of each other.
1415         tolerance = timedelta(seconds=1)
1416         for dummy in range(3):
1417             from_now = self.theclass.utcnow()
1418             from_timestamp = self.theclass.utcfromtimestamp(time.time())
1419             if abs(from_timestamp - from_now) <= tolerance:
1420                 break
1421             # Else try again a few times.
1422         self.failUnless(abs(from_timestamp - from_now) <= tolerance)
1423 
1424     def test_more_timetuple(self):
1425         # This tests fields beyond those tested by the TestDate.test_timetuple.
1426         t = self.theclass(2004, 12, 31, 6, 22, 33)
1427         self.assertEqual(t.timetuple(), (2004, 12, 31, 6, 22, 33, 4, 366, -1))
1428         self.assertEqual(t.timetuple(),
1429                          (t.year, t.month, t.day,
1430                           t.hour, t.minute, t.second,
1431                           t.weekday(),
1432                           t.toordinal() - date(t.year, 1, 1).toordinal() + 1,
1433                           -1))
1434         tt = t.timetuple()
1435         self.assertEqual(tt.tm_year, t.year)
1436         self.assertEqual(tt.tm_mon, t.month)
1437         self.assertEqual(tt.tm_mday, t.day)
1438         self.assertEqual(tt.tm_hour, t.hour)
1439         self.assertEqual(tt.tm_min, t.minute)
1440         self.assertEqual(tt.tm_sec, t.second)
1441         self.assertEqual(tt.tm_wday, t.weekday())
1442         self.assertEqual(tt.tm_yday, t.toordinal() -
1443                                      date(t.year, 1, 1).toordinal() + 1)
1444         self.assertEqual(tt.tm_isdst, -1)
1445 
1446     def test_more_strftime(self):
1447         # This tests fields beyond those tested by the TestDate.test_strftime.
1448         t = self.theclass(2004, 12, 31, 6, 22, 33)
1449         self.assertEqual(t.strftime("%m %d %y %S %M %H %j"),
1450                                     "12 31 04 33 22 06 366")
1451 
1452     def test_extract(self):
1453         dt = self.theclass(2002, 3, 4, 18, 45, 3, 1234)
1454         self.assertEqual(dt.date(), date(2002, 3, 4))
1455         self.assertEqual(dt.time(), time(18, 45, 3, 1234))
1456 
1457     def test_combine(self):
1458         d = date(2002, 3, 4)
1459         t = time(18, 45, 3, 1234)
1460         expected = self.theclass(2002, 3, 4, 18, 45, 3, 1234)
1461         combine = self.theclass.combine
1462         dt = combine(d, t)
1463         self.assertEqual(dt, expected)
1464 
1465         dt = combine(time=t, date=d)
1466         self.assertEqual(dt, expected)
1467 
1468         self.assertEqual(d, dt.date())
1469         self.assertEqual(t, dt.time())
1470         self.assertEqual(dt, combine(dt.date(), dt.time()))
1471 
1472         self.assertRaises(TypeError, combine) # need an arg
1473         self.assertRaises(TypeError, combine, d) # need two args
1474         self.assertRaises(TypeError, combine, t, d) # args reversed
1475         self.assertRaises(TypeError, combine, d, t, 1) # too many args
1476         self.assertRaises(TypeError, combine, "date", "time") # wrong types
1477 
1478     def test_replace(self):
1479         cls = self.theclass
1480         args = [1, 2, 3, 4, 5, 6, 7]
1481         base = cls(*args)
1482         self.assertEqual(base, base.replace())
1483 
1484         i = 0
1485         for name, newval in (("year", 2),
1486                              ("month", 3),
1487                              ("day", 4),
1488                              ("hour", 5),
1489                              ("minute", 6),
1490                              ("second", 7),
1491                              ("microsecond", 8)):
1492             newargs = args[:]
1493             newargs[i] = newval
1494             expected = cls(*newargs)
1495             got = base.replace(**{name: newval})
1496             self.assertEqual(expected, got)
1497             i += 1
1498 
1499         # Out of bounds.
1500         base = cls(2000, 2, 29)
1501         self.assertRaises(ValueError, base.replace, year=2001)
1502 
1503     def test_astimezone(self):
1504         # Pretty boring!  The TZ test is more interesting here.  astimezone()
1505         # simply can't be applied to a naive object.
1506         dt = self.theclass.now()
1507         f = FixedOffset(44, "")
1508         self.assertRaises(TypeError, dt.astimezone) # not enough args
1509         self.assertRaises(TypeError, dt.astimezone, f, f) # too many args
1510         self.assertRaises(TypeError, dt.astimezone, dt) # arg wrong type
1511         self.assertRaises(ValueError, dt.astimezone, f) # naive
1512         self.assertRaises(ValueError, dt.astimezone, tz=f)  # naive
1513 
1514         class Bogus(tzinfo):
1515             def utcoffset(self, dt): return None
1516             def dst(self, dt): return timedelta(0)
1517         bog = Bogus()
1518         self.assertRaises(ValueError, dt.astimezone, bog)   # naive
1519 
1520         class AlsoBogus(tzinfo):
1521             def utcoffset(self, dt): return timedelta(0)
1522             def dst(self, dt): return None
1523         alsobog = AlsoBogus()
1524         self.assertRaises(ValueError, dt.astimezone, alsobog) # also naive
1525 
1526     def test_subclass_datetime(self):
1527 
1528         class C(self.theclass):
1529             theAnswer = 42
1530 
1531             def __new__(cls, *args, **kws):
1532                 temp = kws.copy()
1533                 extra = temp.pop('extra')
1534                 result = self.theclass.__new__(cls, *args, **temp)
1535                 result.extra = extra
1536                 return result
1537 
1538             def newmeth(self, start):
1539                 return start + self.year + self.month + self.second
1540 
1541         args = 2003, 4, 14, 12, 13, 41
1542 
1543         dt1 = self.theclass(*args)
1544         dt2 = C(*args, **{'extra': 7})
1545 
1546         self.assertEqual(dt2.__class__, C)
1547         self.assertEqual(dt2.theAnswer, 42)
1548         self.assertEqual(dt2.extra, 7)
1549         self.assertEqual(dt1.toordinal(), dt2.toordinal())
1550         self.assertEqual(dt2.newmeth(-7), dt1.year + dt1.month +
1551                                           dt1.second - 7)
1552 
1553 class SubclassTime(time):
1554     sub_var = 1
1555 
1556 class TestTime(HarmlessMixedComparison):
1557 
1558     theclass = time
1559 
1560     def test_basic_attributes(self):
1561         t = self.theclass(12, 0)
1562         self.assertEqual(t.hour, 12)
1563         self.assertEqual(t.minute, 0)
1564         self.assertEqual(t.second, 0)
1565         self.assertEqual(t.microsecond, 0)
1566 
1567     def test_basic_attributes_nonzero(self):
1568         # Make sure all attributes are non-zero so bugs in
1569         # bit-shifting access show up.
1570         t = self.theclass(12, 59, 59, 8000)
1571         self.assertEqual(t.hour, 12)
1572         self.assertEqual(t.minute, 59)
1573         self.assertEqual(t.second, 59)
1574         self.assertEqual(t.microsecond, 8000)
1575 
1576     def test_roundtrip(self):
1577         t = self.theclass(1, 2, 3, 4)
1578 
1579         # Verify t -> string -> time identity.
1580         s = repr(t)
1581         self.failUnless(s.startswith('datetime.'))
1582         s = s[9:]
1583         t2 = eval(s)
1584         self.assertEqual(t, t2)
1585 
1586         # Verify identity via reconstructing from pieces.
1587         t2 = self.theclass(t.hour, t.minute, t.second,
1588                            t.microsecond)
1589         self.assertEqual(t, t2)
1590 
1591     def test_comparing(self):
1592         args = [1, 2, 3, 4]
1593         t1 = self.theclass(*args)
1594         t2 = self.theclass(*args)
1595         self.failUnless(t1 == t2)
1596         self.failUnless(t1 <= t2)
1597         self.failUnless(t1 >= t2)
1598         self.failUnless(not t1 != t2)
1599         self.failUnless(not t1 < t2)
1600         self.failUnless(not t1 > t2)
1601         self.assertEqual(cmp(t1, t2), 0)
1602         self.assertEqual(cmp(t2, t1), 0)
1603 
1604         for i in range(len(args)):
1605             newargs = args[:]
1606             newargs[i] = args[i] + 1
1607             t2 = self.theclass(*newargs)   # this is larger than t1
1608             self.failUnless(t1 < t2)
1609             self.failUnless(t2 > t1)
1610             self.failUnless(t1 <= t2)
1611             self.failUnless(t2 >= t1)
1612             self.failUnless(t1 != t2)
1613             self.failUnless(t2 != t1)
1614             self.failUnless(not t1 == t2)
1615             self.failUnless(not t2 == t1)
1616             self.failUnless(not t1 > t2)
1617             self.failUnless(not t2 < t1)
1618             self.failUnless(not t1 >= t2)
1619             self.failUnless(not t2 <= t1)
1620             self.assertEqual(cmp(t1, t2), -1)
1621             self.assertEqual(cmp(t2, t1), 1)
1622 
1623         for badarg in OTHERSTUFF:
1624             self.assertEqual(t1 == badarg, False)
1625             self.assertEqual(t1 != badarg, True)
1626             self.assertEqual(badarg == t1, False)
1627             self.assertEqual(badarg != t1, True)
1628 
1629             self.assertRaises(TypeError, lambda: t1 <= badarg)
1630             self.assertRaises(TypeError, lambda: t1 < badarg)
1631             self.assertRaises(TypeError, lambda: t1 > badarg)
1632             self.assertRaises(TypeError, lambda: t1 >= badarg)
1633             self.assertRaises(TypeError, lambda: badarg <= t1)
1634             self.assertRaises(TypeError, lambda: badarg < t1)
1635             self.assertRaises(TypeError, lambda: badarg > t1)
1636             self.assertRaises(TypeError, lambda: badarg >= t1)
1637 
1638     def test_bad_constructor_arguments(self):
1639         # bad hours
1640         self.theclass(0, 0)    # no exception
1641         self.theclass(23, 0)   # no exception
1642         self.assertRaises(ValueError, self.theclass, -1, 0)
1643         self.assertRaises(ValueError, self.theclass, 24, 0)
1644         # bad minutes
1645         self.theclass(23, 0)    # no exception
1646         self.theclass(23, 59)   # no exception
1647         self.assertRaises(ValueError, self.theclass, 23, -1)
1648         self.assertRaises(ValueError, self.theclass, 23, 60)
1649         # bad seconds
1650         self.theclass(23, 59, 0)    # no exception
1651         self.theclass(23, 59, 59)   # no exception
1652         self.assertRaises(ValueError, self.theclass, 23, 59, -1)
1653         self.assertRaises(ValueError, self.theclass, 23, 59, 60)
1654         # bad microseconds
1655         self.theclass(23, 59, 59, 0)        # no exception
1656         self.theclass(23, 59, 59, 999999)   # no exception
1657         self.assertRaises(ValueError, self.theclass, 23, 59, 59, -1)
1658         self.assertRaises(ValueError, self.theclass, 23, 59, 59, 1000000)
1659 
1660     def test_hash_equality(self):
1661         d = self.theclass(23, 30, 17)
1662         e = self.theclass(23, 30, 17)
1663         self.assertEqual(d, e)
1664         self.assertEqual(hash(d), hash(e))
1665 
1666         dic = {d: 1}
1667         dic[e] = 2
1668         self.assertEqual(len(dic), 1)
1669         self.assertEqual(dic[d], 2)
1670         self.assertEqual(dic[e], 2)
1671 
1672         d = self.theclass(0,  5, 17)
1673         e = self.theclass(0,  5, 17)
1674         self.assertEqual(d, e)
1675         self.assertEqual(hash(d), hash(e))
1676 
1677         dic = {d: 1}
1678         dic[e] = 2
1679         self.assertEqual(len(dic), 1)
1680         self.assertEqual(dic[d], 2)
1681         self.assertEqual(dic[e], 2)
1682 
1683     def test_isoformat(self):
1684         t = self.theclass(4, 5, 1, 123)
1685         self.assertEqual(t.isoformat(), "04:05:01.000123")
1686         self.assertEqual(t.isoformat(), str(t))
1687 
1688         t = self.theclass()
1689         self.assertEqual(t.isoformat(), "00:00:00")
1690         self.assertEqual(t.isoformat(), str(t))
1691 
1692         t = self.theclass(microsecond=1)
1693         self.assertEqual(t.isoformat(), "00:00:00.000001")
1694         self.assertEqual(t.isoformat(), str(t))
1695 
1696         t = self.theclass(microsecond=10)
1697         self.assertEqual(t.isoformat(), "00:00:00.000010")
1698         self.assertEqual(t.isoformat(), str(t))
1699 
1700         t = self.theclass(microsecond=100)
1701         self.assertEqual(t.isoformat(), "00:00:00.000100")
1702         self.assertEqual(t.isoformat(), str(t))
1703 
1704         t = self.theclass(microsecond=1000)
1705         self.assertEqual(t.isoformat(), "00:00:00.001000")
1706         self.assertEqual(t.isoformat(), str(t))
1707 
1708         t = self.theclass(microsecond=10000)
1709         self.assertEqual(t.isoformat(), "00:00:00.010000")
1710         self.assertEqual(t.isoformat(), str(t))
1711 
1712         t = self.theclass(microsecond=100000)
1713         self.assertEqual(t.isoformat(), "00:00:00.100000")
1714         self.assertEqual(t.isoformat(), str(t))
1715 
1716     def test_strftime(self):
1717         t = self.theclass(1, 2, 3, 4)
1718         self.assertEqual(t.strftime('%H %M %S'), "01 02 03")
1719         # A naive object replaces %z and %Z with empty strings.
1720         self.assertEqual(t.strftime("'%z' '%Z'"), "'' ''")
1721 
1722     def test_str(self):
1723         self.assertEqual(str(self.theclass(1, 2, 3, 4)), "01:02:03.000004")
1724         self.assertEqual(str(self.theclass(10, 2, 3, 4000)), "10:02:03.004000")
1725         self.assertEqual(str(self.theclass(0, 2, 3, 400000)), "00:02:03.400000")
1726         self.assertEqual(str(self.theclass(12, 2, 3, 0)), "12:02:03")
1727         self.assertEqual(str(self.theclass(23, 15, 0, 0)), "23:15:00")
1728 
1729     def test_repr(self):
1730         name = 'datetime.' + self.theclass.__name__
1731         self.assertEqual(repr(self.theclass(1, 2, 3, 4)),
1732                          "%s(1, 2, 3, 4)" % name)
1733         self.assertEqual(repr(self.theclass(10, 2, 3, 4000)),
1734                          "%s(10, 2, 3, 4000)" % name)
1735         self.assertEqual(repr(self.theclass(0, 2, 3, 400000)),
1736                          "%s(0, 2, 3, 400000)" % name)
1737         self.assertEqual(repr(self.theclass(12, 2, 3, 0)),
1738                          "%s(12, 2, 3)" % name)
1739         self.assertEqual(repr(self.theclass(23, 15, 0, 0)),
1740                          "%s(23, 15)" % name)
1741 
1742     def test_resolution_info(self):
1743         self.assert_(isinstance(self.theclass.min, self.theclass))
1744         self.assert_(isinstance(self.theclass.max, self.theclass))
1745         self.assert_(isinstance(self.theclass.resolution, timedelta))
1746         self.assert_(self.theclass.max > self.theclass.min)
1747 
1748     def test_pickling(self):
1749         args = 20, 59, 16, 64**2
1750         orig = self.theclass(*args)
1751         for pickler, unpickler, proto in pickle_choices:
1752             green = pickler.dumps(orig, proto)
1753             derived = unpickler.loads(green)
1754             self.assertEqual(orig, derived)
1755 
1756     def test_pickling_subclass_time(self):
1757         args = 20, 59, 16, 64**2
1758         orig = SubclassTime(*args)
1759         for pickler, unpickler, proto in pickle_choices:
1760             green = pickler.dumps(orig, proto)
1761             derived = unpickler.loads(green)
1762             self.assertEqual(orig, derived)
1763 
1764     def test_bool(self):
1765         cls = self.theclass
1766         self.failUnless(cls(1))
1767         self.failUnless(cls(0, 1))
1768         self.failUnless(cls(0, 0, 1))
1769         self.failUnless(cls(0, 0, 0, 1))
1770         self.failUnless(not cls(0))
1771         self.failUnless(not cls())
1772 
1773     def test_replace(self):
1774         cls = self.theclass
1775         args = [1, 2, 3, 4]
1776         base = cls(*args)
1777         self.assertEqual(base, base.replace())
1778 
1779         i = 0
1780         for name, newval in (("hour", 5),
1781                              ("minute", 6),
1782                              ("second", 7),
1783                              ("microsecond", 8)):
1784             newargs = args[:]
1785             newargs[i] = newval
1786             expected = cls(*newargs)
1787             got = base.replace(**{name: newval})
1788             self.assertEqual(expected, got)
1789             i += 1
1790 
1791         # Out of bounds.
1792         base = cls(1)
1793         self.assertRaises(ValueError, base.replace, hour=24)
1794         self.assertRaises(ValueError, base.replace, minute=-1)
1795         self.assertRaises(ValueError, base.replace, second=100)
1796         self.assertRaises(ValueError, base.replace, microsecond=1000000)
1797 
1798     def test_subclass_time(self):
1799 
1800         class C(self.theclass):
1801             theAnswer = 42
1802 
1803             def __new__(cls, *args, **kws):
1804                 temp = kws.copy()
1805                 extra = temp.pop('extra')
1806                 result = self.theclass.__new__(cls, *args, **temp)
1807                 result.extra = extra
1808                 return result
1809 
1810             def newmeth(self, start):
1811                 return start + self.hour + self.second
1812 
1813         args = 4, 5, 6
1814 
1815         dt1 = self.theclass(*args)
1816         dt2 = C(*args, **{'extra': 7})
1817 
1818         self.assertEqual(dt2.__class__, C)
1819         self.assertEqual(dt2.theAnswer, 42)
1820         self.assertEqual(dt2.extra, 7)
1821         self.assertEqual(dt1.isoformat(), dt2.isoformat())
1822         self.assertEqual(dt2.newmeth(-7), dt1.hour + dt1.second - 7)
1823 
1824 # A mixin for classes with a tzinfo= argument.  Subclasses must define
1825 # theclass as a class atribute, and theclass(1, 1, 1, tzinfo=whatever)
1826 # must be legit (which is true for time and datetime).
1827 class TZInfoBase(unittest.TestCase):
1828 
1829     def test_argument_passing(self):
1830         cls = self.theclass
1831         # A datetime passes itself on, a time passes None.
1832         class introspective(tzinfo):
1833             def tzname(self, dt):    return dt and "real" or "none"
1834             def utcoffset(self, dt):
1835                 return timedelta(minutes = dt and 42 or -42)
1836             dst = utcoffset
1837 
1838         obj = cls(1, 2, 3, tzinfo=introspective())
1839 
1840         expected = cls is time and "none" or "real"
1841         self.assertEqual(obj.tzname(), expected)
1842 
1843         expected = timedelta(minutes=(cls is time and -42 or 42))
1844         self.assertEqual(obj.utcoffset(), expected)
1845         self.assertEqual(obj.dst(), expected)
1846 
1847     def test_bad_tzinfo_classes(self):
1848         cls = self.theclass
1849         self.assertRaises(TypeError, cls, 1, 1, 1, tzinfo=12)
1850 
1851         class NiceTry(object):
1852             def __init__(self): pass
1853             def utcoffset(self, dt): pass
1854         self.assertRaises(TypeError, cls, 1, 1, 1, tzinfo=NiceTry)
1855 
1856         class BetterTry(tzinfo):
1857             def __init__(self): pass
1858             def utcoffset(self, dt): pass
1859         b = BetterTry()
1860         t = cls(1, 1, 1, tzinfo=b)
1861         self.failUnless(t.tzinfo is b)
1862 
1863     def test_utc_offset_out_of_bounds(self):
1864         class Edgy(tzinfo):
1865             def __init__(self, offset):
1866                 self.offset = timedelta(minutes=offset)
1867             def utcoffset(self, dt):
1868                 return self.offset
1869 
1870         cls = self.theclass
1871         for offset, legit in ((-1440, False),
1872                               (-1439, True),
1873                               (1439, True),
1874                               (1440, False)):
1875             if cls is time:
1876                 t = cls(1, 2, 3, tzinfo=Edgy(offset))
1877             elif cls is datetime:
1878                 t = cls(6, 6, 6, 1, 2, 3, tzinfo=Edgy(offset))
1879             else:
1880                 assert 0, "impossible"
1881             if legit:
1882                 aofs = abs(offset)
1883                 h, m = divmod(aofs, 60)
1884                 tag = "%c%02d:%02d" % (offset < 0 and '-' or '+', h, m)
1885                 if isinstance(t, datetime):
1886                     t = t.timetz()
1887                 self.assertEqual(str(t), "01:02:03" + tag)
1888             else:
1889                 self.assertRaises(ValueError, str, t)
1890 
1891     def test_tzinfo_classes(self):
1892         cls = self.theclass
1893         class C1(tzinfo):
1894             def utcoffset(self, dt): return None
1895             def dst(self, dt): return None
1896             def tzname(self, dt): return None
1897         for t in (cls(1, 1, 1),
1898                   cls(1, 1, 1, tzinfo=None),
1899                   cls(1, 1, 1, tzinfo=C1())):
1900             self.failUnless(t.utcoffset() is None)
1901             self.failUnless(t.dst() is None)
1902             self.failUnless(t.tzname() is None)
1903 
1904         class C3(tzinfo):
1905             def utcoffset(self, dt): return timedelta(minutes=-1439)
1906             def dst(self, dt): return timedelta(minutes=1439)
1907             def tzname(self, dt): return "aname"
1908         t = cls(1, 1, 1, tzinfo=C3())
1909         self.assertEqual(t.utcoffset(), timedelta(minutes=-1439))
1910         self.assertEqual(t.dst(), timedelta(minutes=1439))
1911         self.assertEqual(t.tzname(), "aname")
1912 
1913         # Wrong types.
1914         class C4(tzinfo):
1915             def utcoffset(self, dt): return "aname"
1916             def dst(self, dt): return 7
1917             def tzname(self, dt): return 0
1918         t = cls(1, 1, 1, tzinfo=C4())
1919         self.assertRaises(TypeError, t.utcoffset)
1920         self.assertRaises(TypeError, t.dst)
1921         self.assertRaises(TypeError, t.tzname)
1922 
1923         # Offset out of range.
1924         class C6(tzinfo):
1925             def utcoffset(self, dt): return timedelta(hours=-24)
1926             def dst(self, dt): return timedelta(hours=24)
1927         t = cls(1, 1, 1, tzinfo=C6())
1928         self.assertRaises(ValueError, t.utcoffset)
1929         self.assertRaises(ValueError, t.dst)
1930 
1931         # Not a whole number of minutes.
1932         class C7(tzinfo):
1933             def utcoffset(self, dt): return timedelta(seconds=61)
1934             def dst(self, dt): return timedelta(microseconds=-81)
1935         t = cls(1, 1, 1, tzinfo=C7())
1936         self.assertRaises(ValueError, t.utcoffset)
1937         self.assertRaises(ValueError, t.dst)
1938 
1939     def test_aware_compare(self):
1940         cls = self.theclass
1941 
1942         # Ensure that utcoffset() gets ignored if the comparands have
1943         # the same tzinfo member.
1944         class OperandDependentOffset(tzinfo):
1945             def utcoffset(self, t):
1946                 if t.minute < 10:
1947                     # d0 and d1 equal after adjustment
1948                     return timedelta(minutes=t.minute)
1949                 else:
1950                     # d2 off in the weeds
1951                     return timedelta(minutes=59)
1952 
1953         base = cls(8, 9, 10, tzinfo=OperandDependentOffset())
1954         d0 = base.replace(minute=3)
1955         d1 = base.replace(minute=9)
1956         d2 = base.replace(minute=11)
1957         for x in d0, d1, d2:
1958             for y in d0, d1, d2:
1959                 got = cmp(x, y)
1960                 expected = cmp(x.minute, y.minute)
1961                 self.assertEqual(got, expected)
1962 
1963         # However, if they're different members, uctoffset is not ignored.
1964         # Note that a time can't actually have an operand-depedent offset,
1965         # though (and time.utcoffset() passes None to tzinfo.utcoffset()),
1966         # so skip this test for time.
1967         if cls is not time:
1968             d0 = base.replace(minute=3, tzinfo=OperandDependentOffset())
1969             d1 = base.replace(minute=9, tzinfo=OperandDependentOffset())
1970             d2 = base.replace(minute=11, tzinfo=OperandDependentOffset())
1971             for x in d0, d1, d2:
1972                 for y in d0, d1, d2:
1973                     got = cmp(x, y)
1974                     if (x is d0 or x is d1) and (y is d0 or y is d1):
1975                         expected = 0
1976                     elif x is y is d2:
1977                         expected = 0
1978                     elif x is d2:
1979                         expected = -1
1980                     else:
1981                         assert y is d2
1982                         expected = 1
1983                     self.assertEqual(got, expected)
1984 
1985 
1986 # Testing time objects with a non-None tzinfo.
1987 class TestTimeTZ(TestTime, TZInfoBase):
1988     theclass = time
1989 
1990     def test_empty(self):
1991         t = self.theclass()
1992         self.assertEqual(t.hour, 0)
1993         self.assertEqual(t.minute, 0)
1994         self.assertEqual(t.second, 0)
1995         self.assertEqual(t.microsecond, 0)
1996         self.failUnless(t.tzinfo is None)
1997 
1998     def test_zones(self):
1999         est = FixedOffset(-300, "EST", 1)
2000         utc = FixedOffset(0, "UTC", -2)
2001         met = FixedOffset(60, "MET", 3)
2002         t1 = time( 7, 47, tzinfo=est)
2003         t2 = time(12, 47, tzinfo=utc)
2004         t3 = time(13, 47, tzinfo=met)
2005         t4 = time(microsecond=40)
2006         t5 = time(microsecond=40, tzinfo=utc)
2007 
2008         self.assertEqual(t1.tzinfo, est)
2009         self.assertEqual(t2.tzinfo, utc)
2010         self.assertEqual(t3.tzinfo, met)
2011         self.failUnless(t4.tzinfo is None)
2012         self.assertEqual(t5.tzinfo, utc)
2013 
2014         self.assertEqual(t1.utcoffset(), timedelta(minutes=-300))
2015         self.assertEqual(t2.utcoffset(), timedelta(minutes=0))
2016         self.assertEqual(t3.utcoffset(), timedelta(minutes=60))
2017         self.failUnless(t4.utcoffset() is None)
2018         self.assertRaises(TypeError, t1.utcoffset, "no args")
2019 
2020         self.assertEqual(t1.tzname(), "EST")
2021         self.assertEqual(t2.tzname(), "UTC")
2022         self.assertEqual(t3.tzname(), "MET")
2023         self.failUnless(t4.tzname() is None)
2024         self.assertRaises(TypeError, t1.tzname, "no args")
2025 
2026         self.assertEqual(t1.dst(), timedelta(minutes=1))
2027         self.assertEqual(t2.dst(), timedelta(minutes=-2))
2028         self.assertEqual(t3.dst(), timedelta(minutes=3))
2029         self.failUnless(t4.dst() is None)
2030         self.assertRaises(TypeError, t1.dst, "no args")
2031 
2032         self.assertEqual(hash(t1), hash(t2))
2033         self.assertEqual(hash(t1), hash(t3))
2034         self.assertEqual(hash(t2), hash(t3))
2035 
2036         self.assertEqual(t1, t2)
2037         self.assertEqual(t1, t3)
2038         self.assertEqual(t2, t3)
2039         self.assertRaises(TypeError, lambda: t4 == t5) # mixed tz-aware & naive
2040         self.assertRaises(TypeError, lambda: t4 < t5) # mixed tz-aware & naive
2041         self.assertRaises(TypeError, lambda: t5 < t4) # mixed tz-aware & naive
2042 
2043         self.assertEqual(str(t1), "07:47:00-05:00")
2044         self.assertEqual(str(t2), "12:47:00+00:00")
2045         self.assertEqual(str(t3), "13:47:00+01:00")
2046         self.assertEqual(str(t4), "00:00:00.000040")
2047         self.assertEqual(str(t5), "00:00:00.000040+00:00")
2048 
2049         self.assertEqual(t1.isoformat(), "07:47:00-05:00")
2050         self.assertEqual(t2.isoformat(), "12:47:00+00:00")
2051         self.assertEqual(t3.isoformat(), "13:47:00+01:00")
2052         self.assertEqual(t4.isoformat(), "00:00:00.000040")
2053         self.assertEqual(t5.isoformat(), "00:00:00.000040+00:00")
2054 
2055         d = 'datetime.time'
2056         self.assertEqual(repr(t1), d + "(7, 47, tzinfo=est)")
2057         self.assertEqual(repr(t2), d + "(12, 47, tzinfo=utc)")
2058         self.assertEqual(repr(t3), d + "(13, 47, tzinfo=met)")
2059         self.assertEqual(repr(t4), d + "(0, 0, 0, 40)")
2060         self.assertEqual(repr(t5), d + "(0, 0, 0, 40, tzinfo=utc)")
2061 
2062         self.assertEqual(t1.strftime("%H:%M:%S %%Z=%Z %%z=%z"),
2063                                      "07:47:00 %Z=EST %z=-0500")
2064         self.assertEqual(t2.strftime("%H:%M:%S %Z %z"), "12:47:00 UTC +0000")
2065         self.assertEqual(t3.strftime("%H:%M:%S %Z %z"), "13:47:00 MET +0100")
2066 
2067         yuck = FixedOffset(-1439, "%z %Z %%z%%Z")
2068         t1 = time(23, 59, tzinfo=yuck)
2069         self.assertEqual(t1.strftime("%H:%M %%Z='%Z' %%z='%z'"),
2070                                      "23:59 %Z='%z %Z %%z%%Z' %z='-2359'")
2071 
2072         # Check that an invalid tzname result raises an exception.
2073         class Badtzname(tzinfo):
2074             def tzname(self, dt): return 42
2075         t = time(2, 3, 4, tzinfo=Badtzname())
2076         self.assertEqual(t.strftime("%H:%M:%S"), "02:03:04")
2077         self.assertRaises(TypeError, t.strftime, "%Z")
2078 
2079     def test_hash_edge_cases(self):
2080         # Offsets that overflow a basic time.
2081         t1 = self.theclass(0, 1, 2, 3, tzinfo=FixedOffset(1439, ""))
2082         t2 = self.theclass(0, 0, 2, 3, tzinfo=FixedOffset(1438, ""))
2083         self.assertEqual(hash(t1), hash(t2))
2084 
2085         t1 = self.theclass(23, 58, 6, 100, tzinfo=FixedOffset(-1000, ""))
2086         t2 = self.theclass(23, 48, 6, 100, tzinfo=FixedOffset(-1010, ""))
2087         self.assertEqual(hash(t1), hash(t2))
2088 
2089     def test_pickling(self):
2090         # Try one without a tzinfo.
2091         args = 20, 59, 16, 64**2
2092         orig = self.theclass(*args)
2093         for pickler, unpickler, proto in pickle_choices:
2094             green = pickler.dumps(orig, proto)
2095             derived = unpickler.loads(green)
2096             self.assertEqual(orig, derived)
2097 
2098         # Try one with a tzinfo.
2099         tinfo = PicklableFixedOffset(-300, 'cookie')
2100         orig = self.theclass(5, 6, 7, tzinfo=tinfo)
2101         for pickler, unpickler, proto in pickle_choices:
2102             green = pickler.dumps(orig, proto)
2103             derived = unpickler.loads(green)
2104             self.assertEqual(orig, derived)
2105             self.failUnless(isinstance(derived.tzinfo, PicklableFixedOffset))
2106             self.assertEqual(derived.utcoffset(), timedelta(minutes=-300))
2107             self.assertEqual(derived.tzname(), 'cookie')
2108 
2109     def test_more_bool(self):
2110         # Test cases with non-None tzinfo.
2111         cls = self.theclass
2112 
2113         t = cls(0, tzinfo=FixedOffset(-300, ""))
2114         self.failUnless(t)
2115 
2116         t = cls(5, tzinfo=FixedOffset(-300, ""))
2117         self.failUnless(t)
2118 
2119         t = cls(5, tzinfo=FixedOffset(300, ""))
2120         self.failUnless(not t)
2121 
2122         t = cls(23, 59, tzinfo=FixedOffset(23*60 + 59, ""))
2123         self.failUnless(not t)
2124 
2125         # Mostly ensuring this doesn't overflow internally.
2126         t = cls(0, tzinfo=FixedOffset(23*60 + 59, ""))
2127         self.failUnless(t)
2128 
2129         # But this should yield a value error -- the utcoffset is bogus.
2130         t = cls(0, tzinfo=FixedOffset(24*60, ""))
2131         self.assertRaises(ValueError, lambda: bool(t))
2132 
2133         # Likewise.
2134         t = cls(0, tzinfo=FixedOffset(-24*60, ""))
2135         self.assertRaises(ValueError, lambda: bool(t))
2136 
2137     def test_replace(self):
2138         cls = self.theclass
2139         z100 = FixedOffset(100, "+100")
2140         zm200 = FixedOffset(timedelta(minutes=-200), "-200")
2141         args = [1, 2, 3, 4, z100]
2142         base = cls(*args)
2143         self.assertEqual(base, base.replace())
2144 
2145         i = 0
2146         for name, newval in (("hour", 5),
2147                              ("minute", 6),
2148                              ("second", 7),
2149                              ("microsecond", 8),
2150                              ("tzinfo", zm200)):
2151             newargs = args[:]
2152             newargs[i] = newval
2153             expected = cls(*newargs)
2154             got = base.replace(**{name: newval})
2155             self.assertEqual(expected, got)
2156             i += 1
2157 
2158         # Ensure we can get rid of a tzinfo.
2159         self.assertEqual(base.tzname(), "+100")
2160         base2 = base.replace(tzinfo=None)
2161         self.failUnless(base2.tzinfo is None)
2162         self.failUnless(base2.tzname() is None)
2163 
2164         # Ensure we can add one.
2165         base3 = base2.replace(tzinfo=z100)
2166         self.assertEqual(base, base3)
2167         self.failUnless(base.tzinfo is base3.tzinfo)
2168 
2169         # Out of bounds.
2170         base = cls(1)
2171         self.assertRaises(ValueError, base.replace, hour=24)
2172         self.assertRaises(ValueError, base.replace, minute=-1)
2173         self.assertRaises(ValueError, base.replace, second=100)
2174         self.assertRaises(ValueError, base.replace, microsecond=1000000)
2175 
2176     def test_mixed_compare(self):
2177         t1 = time(1, 2, 3)
2178         t2 = time(1, 2, 3)
2179         self.assertEqual(t1, t2)
2180         t2 = t2.replace(tzinfo=None)
2181         self.assertEqual(t1, t2)
2182         t2 = t2.replace(tzinfo=FixedOffset(None, ""))
2183         self.assertEqual(t1, t2)
2184         t2 = t2.replace(tzinfo=FixedOffset(0, ""))
2185         self.assertRaises(TypeError, lambda: t1 == t2)
2186 
2187         # In time w/ identical tzinfo objects, utcoffset is ignored.
2188         class Varies(tzinfo):
2189             def __init__(self):
2190                 self.offset = timedelta(minutes=22)
2191             def utcoffset(self, t):
2192                 self.offset += timedelta(minutes=1)
2193                 return self.offset
2194 
2195         v = Varies()
2196         t1 = t2.replace(tzinfo=v)
2197         t2 = t2.replace(tzinfo=v)
2198         self.assertEqual(t1.utcoffset(), timedelta(minutes=23))
2199         self.assertEqual(t2.utcoffset(), timedelta(minutes=24))
2200         self.assertEqual(t1, t2)
2201 
2202         # But if they're not identical, it isn't ignored.
2203         t2 = t2.replace(tzinfo=Varies())
2204         self.failUnless(t1 < t2)  # t1's offset counter still going up
2205 
2206     def test_subclass_timetz(self):
2207 
2208         class C(self.theclass):
2209             theAnswer = 42
2210 
2211             def __new__(cls, *args, **kws):
2212                 temp = kws.copy()
2213                 extra = temp.pop('extra')
2214                 result = self.theclass.__new__(cls, *args, **temp)
2215                 result.extra = extra
2216                 return result
2217 
2218             def newmeth(self, start):
2219                 return start + self.hour + self.second
2220 
2221         args = 4, 5, 6, 500, FixedOffset(-300, "EST", 1)
2222 
2223         dt1 = self.theclass(*args)
2224         dt2 = C(*args, **{'extra': 7})
2225 
2226         self.assertEqual(dt2.__class__, C)
2227         self.assertEqual(dt2.theAnswer, 42)
2228         self.assertEqual(dt2.extra, 7)
2229         self.assertEqual(dt1.utcoffset(), dt2.utcoffset())
2230         self.assertEqual(dt2.newmeth(-7), dt1.hour + dt1.second - 7)
2231 
2232 
2233 # Testing datetime objects with a non-None tzinfo.
2234 
2235 class TestDateTimeTZ(TestDateTime, TZInfoBase):
2236     theclass = datetime
2237 
2238     def test_trivial(self):
2239         dt = self.theclass(1, 2, 3, 4, 5, 6, 7)
2240         self.assertEqual(dt.year, 1)
2241         self.assertEqual(dt.month, 2)
2242         self.assertEqual(dt.day, 3)
2243         self.assertEqual(dt.hour, 4)
2244         self.assertEqual(dt.minute, 5)
2245         self.assertEqual(dt.second, 6)
2246         self.assertEqual(dt.microsecond, 7)
2247         self.assertEqual(dt.tzinfo, None)
2248 
2249     def test_even_more_compare(self):
2250         # The test_compare() and test_more_compare() inherited from TestDate
2251         # and TestDateTime covered non-tzinfo cases.
2252 
2253         # Smallest possible after UTC adjustment.
2254         t1 = self.theclass(1, 1, 1, tzinfo=FixedOffset(1439, ""))
2255         # Largest possible after UTC adjustment.
2256         t2 = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999999,
2257                            tzinfo=FixedOffset(-1439, ""))
2258 
2259         # Make sure those compare correctly, and w/o overflow.
2260         self.failUnless(t1 < t2)
2261         self.failUnless(t1 != t2)
2262         self.failUnless(t2 > t1)
2263 
2264         self.failUnless(t1 == t1)
2265         self.failUnless(t2 == t2)
2266 
2267         # Equal afer adjustment.
2268         t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(1, ""))
2269         t2 = self.theclass(2, 1, 1, 3, 13, tzinfo=FixedOffset(3*60+13+2, ""))
2270         self.assertEqual(t1, t2)
2271 
2272         # Change t1 not to subtract a minute, and t1 should be larger.
2273         t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(0, ""))
2274         self.failUnless(t1 > t2)
2275 
2276         # Change t1 to subtract 2 minutes, and t1 should be smaller.
2277         t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(2, ""))
2278         self.failUnless(t1 < t2)
2279 
2280         # Back to the original t1, but make seconds resolve it.
2281         t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(1, ""),
2282                            second=1)
2283         self.failUnless(t1 > t2)
2284 
2285         # Likewise, but make microseconds resolve it.
2286         t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(1, ""),
2287                            microsecond=1)
2288         self.failUnless(t1 > t2)
2289 
2290         # Make t2 naive and it should fail.
2291         t2 = self.theclass.min
2292         self.assertRaises(TypeError, lambda: t1 == t2)
2293         self.assertEqual(t2, t2)
2294 
2295         # It's also naive if it has tzinfo but tzinfo.utcoffset() is None.
2296         class Naive(tzinfo):
2297             def utcoffset(self, dt): return None
2298         t2 = self.theclass(5, 6, 7, tzinfo=Naive())
2299         self.assertRaises(TypeError, lambda: t1 == t2)
2300         self.assertEqual(t2, t2)
2301 
2302         # OTOH, it's OK to compare two of these mixing the two ways of being
2303         # naive.
2304         t1 = self.theclass(5, 6, 7)
2305         self.assertEqual(t1, t2)
2306 
2307         # Try a bogus uctoffset.
2308         class Bogus(tzinfo):
2309             def utcoffset(self, dt):
2310                 return timedelta(minutes=1440) # out of bounds
2311         t1 = self.theclass(2, 2, 2, tzinfo=Bogus())
2312         t2 = self.theclass(2, 2, 2, tzinfo=FixedOffset(0, ""))
2313         self.assertRaises(ValueError, lambda: t1 == t2)
2314 
2315     def test_pickling(self):
2316         # Try one without a tzinfo.
2317         args = 6, 7, 23, 20, 59, 1, 64**2
2318         orig = self.theclass(*args)
2319         for pickler, unpickler, proto in pickle_choices:
2320             green = pickler.dumps(orig, proto)
2321             derived = unpickler.loads(green)
2322             self.assertEqual(orig, derived)
2323 
2324         # Try one with a tzinfo.
2325         tinfo = PicklableFixedOffset(-300, 'cookie')
2326         orig = self.theclass(*args, **{'tzinfo': tinfo})
2327         derived = self.theclass(1, 1, 1, tzinfo=FixedOffset(0, "", 0))
2328         for pickler, unpickler, proto in pickle_choices:
2329             green = pickler.dumps(orig, proto)
2330             derived = unpickler.loads(green)
2331             self.assertEqual(orig, derived)
2332             self.failUnless(isinstance(derived.tzinfo,
2333                             PicklableFixedOffset))
2334             self.assertEqual(derived.utcoffset(), timedelta(minutes=-300))
2335             self.assertEqual(derived.tzname(), 'cookie')
2336 
2337     def test_extreme_hashes(self):
2338         # If an attempt is made to hash these via subtracting the offset
2339         # then hashing a datetime object, OverflowError results.  The
2340         # Python implementation used to blow up here.
2341         t = self.theclass(1, 1, 1, tzinfo=FixedOffset(1439, ""))
2342         hash(t)
2343         t = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999999,
2344                           tzinfo=FixedOffset(-1439, ""))
2345         hash(t)
2346 
2347         # OTOH, an OOB offset should blow up.
2348         t = self.theclass(5, 5, 5, tzinfo=FixedOffset(-1440, ""))
2349         self.assertRaises(ValueError, hash, t)
2350 
2351     def test_zones(self):
2352         est = FixedOffset(-300, "EST")
2353         utc = FixedOffset(0, "UTC")
2354         met = FixedOffset(60, "MET")
2355         t1 = datetime(2002, 3, 19,  7, 47, tzinfo=est)
2356         t2 = datetime(2002, 3, 19, 12, 47, tzinfo=utc)
2357         t3 = datetime(2002, 3, 19, 13, 47, tzinfo=met)
2358         self.assertEqual(t1.tzinfo, est)
2359         self.assertEqual(t2.tzinfo, utc)
2360         self.assertEqual(t3.tzinfo, met)
2361         self.assertEqual(t1.utcoffset(), timedelta(minutes=-300))
2362         self.assertEqual(t2.utcoffset(), timedelta(minutes=0))
2363         self.assertEqual(t3.utcoffset(), timedelta(minutes=60))
2364         self.assertEqual(t1.tzname(), "EST")
2365         self.assertEqual(t2.tzname(), "UTC")
2366         self.assertEqual(t3.tzname(), "MET")
2367         self.assertEqual(hash(t1), hash(t2))
2368         self.assertEqual(hash(t1), hash(t3))
2369         self.assertEqual(hash(t2), hash(t3))
2370         self.assertEqual(t1, t2)
2371         self.assertEqual(t1, t3)
2372         self.assertEqual(t2, t3)
2373         self.assertEqual(str(t1), "2002-03-19 07:47:00-05:00")
2374         self.assertEqual(str(t2), "2002-03-19 12:47:00+00:00")
2375         self.assertEqual(str(t3), "2002-03-19 13:47:00+01:00")
2376         d = 'datetime.datetime(2002, 3, 19, '
2377         self.assertEqual(repr(t1), d + "7, 47, tzinfo=est)")
2378         self.assertEqual(repr(t2), d + "12, 47, tzinfo=utc)")
2379         self.assertEqual(repr(t3), d + "13, 47, tzinfo=met)")
2380 
2381     def test_combine(self):
2382         met = FixedOffset(60, "MET")
2383         d = date(2002, 3, 4)
2384         tz = time(18, 45, 3, 1234, tzinfo=met)
2385         dt = datetime.combine(d, tz)
2386         self.assertEqual(dt, datetime(2002, 3, 4, 18, 45, 3, 1234,
2387                                         tzinfo=met))
2388 
2389     def test_extract(self):
2390         met = FixedOffset(60, "MET")
2391         dt = self.theclass(2002, 3, 4, 18, 45, 3, 1234, tzinfo=met)
2392         self.assertEqual(dt.date(), date(2002, 3, 4))
2393         self.assertEqual(dt.time(), time(18, 45, 3, 1234))
2394         self.assertEqual(dt.timetz(), time(18, 45, 3, 1234, tzinfo=met))
2395 
2396     def test_tz_aware_arithmetic(self):
2397         import random
2398 
2399         now = self.theclass.now()
2400         tz55 = FixedOffset(-330, "west 5:30")
2401         timeaware = now.time().replace(tzinfo=tz55)
2402         nowaware = self.theclass.combine(now.date(), timeaware)
2403         self.failUnless(nowaware.tzinfo is tz55)
2404         self.assertEqual(nowaware.timetz(), timeaware)
2405 
2406         # Can't mix aware and non-aware.
2407         self.assertRaises(TypeError, lambda: now - nowaware)
2408         self.assertRaises(TypeError, lambda: nowaware - now)
2409 
2410         # And adding datetime's doesn't make sense, aware or not.
2411         self.assertRaises(TypeError, lambda: now + nowaware)
2412         self.assertRaises(TypeError, lambda: nowaware + now)
2413         self.assertRaises(TypeError, lambda: nowaware + nowaware)
2414 
2415         # Subtracting should yield 0.
2416         self.assertEqual(now - now, timedelta(0))
2417         self.assertEqual(nowaware - nowaware, timedelta(0))
2418 
2419         # Adding a delta should preserve tzinfo.
2420         delta = timedelta(weeks=1, minutes=12, microseconds=5678)
2421         nowawareplus = nowaware + delta
2422         self.failUnless(nowaware.tzinfo is tz55)
2423         nowawareplus2 = delta + nowaware
2424         self.failUnless(nowawareplus2.tzinfo is tz55)
2425         self.assertEqual(nowawareplus, nowawareplus2)
2426 
2427         # that - delta should be what we started with, and that - what we
2428         # started with should be delta.
2429         diff = nowawareplus - delta
2430         self.failUnless(diff.tzinfo is tz55)
2431         self.assertEqual(nowaware, diff)
2432         self.assertRaises(TypeError, lambda: delta - nowawareplus)
2433         self.assertEqual(nowawareplus - nowaware, delta)
2434 
2435         # Make up a random timezone.
2436         tzr = FixedOffset(random.randrange(-1439, 1440), "randomtimezone")
2437         # Attach it to nowawareplus.
2438         nowawareplus = nowawareplus.replace(tzinfo=tzr)
2439         self.failUnless(nowawareplus.tzinfo is tzr)
2440         # Make sure the difference takes the timezone adjustments into account.
2441         got = nowaware - nowawareplus
2442         # Expected:  (nowaware base - nowaware offset) -
2443         #            (nowawareplus base - nowawareplus offset) =
2444         #            (nowaware base - nowawareplus base) +
2445         #            (nowawareplus offset - nowaware offset) =
2446         #            -delta + nowawareplus offset - nowaware offset
2447         expected = nowawareplus.utcoffset() - nowaware.utcoffset() - delta
2448         self.assertEqual(got, expected)
2449 
2450         # Try max possible difference.
2451         min = self.theclass(1, 1, 1, tzinfo=FixedOffset(1439, "min"))
2452         max = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999999,
2453                             tzinfo=FixedOffset(-1439, "max"))
2454         maxdiff = max - min
2455         self.assertEqual(maxdiff, self.theclass.max - self.theclass.min +
2456                                   timedelta(minutes=2*1439))
2457 
2458     def test_tzinfo_now(self):
2459         meth = self.theclass.now
2460         # Ensure it doesn't require tzinfo (i.e., that this doesn't blow up).
2461         base = meth()
2462         # Try with and without naming the keyword.
2463         off42 = FixedOffset(42, "42")
2464         another = meth(off42)
2465         again = meth(tz=off42)
2466         self.failUnless(another.tzinfo is again.tzinfo)
2467         self.assertEqual(another.utcoffset(), timedelta(minutes=42))
2468         # Bad argument with and w/o naming the keyword.
2469         self.assertRaises(TypeError, meth, 16)
2470         self.assertRaises(TypeError, meth, tzinfo=16)
2471         # Bad keyword name.
2472         self.assertRaises(TypeError, meth, tinfo=off42)
2473         # Too many args.
2474         self.assertRaises(TypeError, meth, off42, off42)
2475 
2476         # We don't know which time zone we're in, and don't have a tzinfo
2477         # class to represent it, so seeing whether a tz argument actually
2478         # does a conversion is tricky.
2479         weirdtz = FixedOffset(timedelta(hours=15, minutes=58), "weirdtz", 0)
2480         utc = FixedOffset(0, "utc", 0)
2481         for dummy in range(3):
2482             now = datetime.now(weirdtz)
2483             self.failUnless(now.tzinfo is weirdtz)
2484             utcnow = datetime.utcnow().replace(tzinfo=utc)
2485             now2 = utcnow.astimezone(weirdtz)
2486             if abs(now - now2) < timedelta(seconds=30):
2487                 break
2488             # Else the code is broken, or more than 30 seconds passed between
2489             # calls; assuming the latter, just try again.
2490         else:
2491             # Three strikes and we're out.
2492             self.fail("utcnow(), now(tz), or astimezone() may be broken")
2493 
2494     def test_tzinfo_fromtimestamp(self):
2495         import time
2496         meth = self.theclass.fromtimestamp
2497         ts = time.time()
2498         # Ensure it doesn't require tzinfo (i.e., that this doesn't blow up).
2499         base = meth(ts)
2500         # Try with and without naming the keyword.
2501         off42 = FixedOffset(42, "42")
2502         another = meth(ts, off42)
2503         again = meth(ts, tz=off42)
2504         self.failUnless(another.tzinfo is again.tzinfo)
2505         self.assertEqual(another.utcoffset(), timedelta(minutes=42))
2506         # Bad argument with and w/o naming the keyword.
2507         self.assertRaises(TypeError, meth, ts, 16)
2508         self.assertRaises(TypeError, meth, ts, tzinfo=16)
2509         # Bad keyword name.
2510         self.assertRaises(TypeError, meth, ts, tinfo=off42)
2511         # Too many args.
2512         self.assertRaises(TypeError, meth, ts, off42, off42)
2513         # Too few args.
2514         self.assertRaises(TypeError, meth)
2515 
2516         # Try to make sure tz= actually does some conversion.
2517         timestamp = 1000000000
2518         utcdatetime = datetime.utcfromtimestamp(timestamp)
2519         # In POSIX (epoch 1970), that's 2001-09-09 01:46:40 UTC, give or take.
2520         # But on some flavor of Mac, it's nowhere near that.  So we can't have
2521         # any idea here what time that actually is, we can only test that
2522         # relative changes match.
2523         utcoffset = timedelta(hours=-15, minutes=39) # arbitrary, but not zero
2524         tz = FixedOffset(utcoffset, "tz", 0)
2525         expected = utcdatetime + utcoffset
2526         got = datetime.fromtimestamp(timestamp, tz)
2527         self.assertEqual(expected, got.replace(tzinfo=None))
2528 
2529     def test_tzinfo_utcnow(self):
2530         meth = self.theclass.utcnow
2531         # Ensure it doesn't require tzinfo (i.e., that this doesn't blow up).
2532         base = meth()
2533         # Try with and without naming the keyword; for whatever reason,
2534         # utcnow() doesn't accept a tzinfo argument.
2535         off42 = FixedOffset(42, "42")
2536         self.assertRaises(TypeError, meth, off42)
2537         self.assertRaises(TypeError, meth, tzinfo=off42)
2538 
2539     def test_tzinfo_utcfromtimestamp(self):
2540         import time
2541         meth = self.theclass.utcfromtimestamp
2542         ts = time.time()
2543         # Ensure it doesn't require tzinfo (i.e., that this doesn't blow up).
2544         base = meth(ts)
2545         # Try with and without naming the keyword; for whatever reason,
2546         # utcfromtimestamp() doesn't accept a tzinfo argument.
2547         off42 = FixedOffset(42, "42")
2548         self.assertRaises(TypeError, meth, ts, off42)
2549         self.assertRaises(TypeError, meth, ts, tzinfo=off42)
2550 
2551     def test_tzinfo_timetuple(self):
2552         # TestDateTime tested most of this.  datetime adds a twist to the
2553         # DST flag.
2554         class DST(tzinfo):
2555             def __init__(self, dstvalue):
2556                 if isinstance(dstvalue, int):
2557                     dstvalue = timedelta(minutes=dstvalue)
2558                 self.dstvalue = dstvalue
2559             def dst(self, dt):
2560                 return self.dstvalue
2561 
2562         cls = self.theclass
2563         for dstvalue, flag in (-33, 1), (33, 1), (0, 0), (None, -1):
2564             d = cls(1, 1, 1, 10, 20, 30, 40, tzinfo=DST(dstvalue))
2565             t = d.timetuple()
2566             self.assertEqual(1, t.tm_year)
2567             self.assertEqual(1, t.tm_mon)
2568             self.assertEqual(1, t.tm_mday)
2569             self.assertEqual(10, t.tm_hour)
2570             self.assertEqual(20, t.tm_min)
2571             self.assertEqual(30, t.tm_sec)
2572             self.assertEqual(0, t.tm_wday)
2573             self.assertEqual(1, t.tm_yday)
2574             self.assertEqual(flag, t.tm_isdst)
2575 
2576         # dst() returns wrong type.
2577         self.assertRaises(TypeError, cls(1, 1, 1, tzinfo=DST("x")).timetuple)
2578 
2579         # dst() at the edge.
2580         self.assertEqual(cls(1,1,1, tzinfo=DST(1439)).timetuple().tm_isdst, 1)
2581         self.assertEqual(cls(1,1,1, tzinfo=DST(-1439)).timetuple().tm_isdst, 1)
2582 
2583         # dst() out of range.
2584         self.assertRaises(ValueError, cls(1,1,1, tzinfo=DST(1440)).timetuple)
2585         self.assertRaises(ValueError, cls(1,1,1, tzinfo=DST(-1440)).timetuple)
2586 
2587     def test_utctimetuple(self):
2588         class DST(tzinfo):
2589             def __init__(self, dstvalue):
2590                 if isinstance(dstvalue, int):
2591                     dstvalue = timedelta(minutes=dstvalue)
2592                 self.dstvalue = dstvalue
2593             def dst(self, dt):
2594                 return self.dstvalue
2595 
2596         cls = self.theclass
2597         # This can't work:  DST didn't implement utcoffset.
2598         self.assertRaises(NotImplementedError,
2599                           cls(1, 1, 1, tzinfo=DST(0)).utcoffset)
2600 
2601         class UOFS(DST):
2602             def __init__(self, uofs, dofs=None):
2603                 DST.__init__(self, dofs)
2604                 self.uofs = timedelta(minutes=uofs)
2605             def utcoffset(self, dt):
2606                 return self.uofs
2607 
2608         # Ensure tm_isdst is 0 regardless of what dst() says:  DST is never
2609         # in effect for a UTC time.
2610         for dstvalue in -33, 33, 0, None:
2611             d = cls(1, 2, 3, 10, 20, 30, 40, tzinfo=UOFS(-53, dstvalue))
2612             t = d.utctimetuple()
2613             self.assertEqual(d.year, t.tm_year)
2614             self.assertEqual(d.month, t.tm_mon)
2615             self.assertEqual(d.day, t.tm_mday)
2616             self.assertEqual(11, t.tm_hour) # 20mm + 53mm = 1hn + 13mm
2617             self.assertEqual(13, t.tm_min)
2618             self.assertEqual(d.second, t.tm_sec)
2619             self.assertEqual(d.weekday(), t.tm_wday)
2620             self.assertEqual(d.toordinal() - date(1, 1, 1).toordinal() + 1,
2621                              t.tm_yday)
2622             self.assertEqual(0, t.tm_isdst)
2623 
2624         # At the edges, UTC adjustment can normalize into years out-of-range
2625         # for a datetime object.  Ensure that a correct timetuple is
2626         # created anyway.
2627         tiny = cls(MINYEAR, 1, 1, 0, 0, 37, tzinfo=UOFS(1439))
2628         # That goes back 1 minute less than a full day.
2629         t = tiny.utctimetuple()
2630         self.assertEqual(t.tm_year, MINYEAR-1)
2631         self.assertEqual(t.tm_mon, 12)
2632         self.assertEqual(t.tm_mday, 31)
2633         self.assertEqual(t.tm_hour, 0)
2634         self.assertEqual(t.tm_min, 1)
2635         self.assertEqual(t.tm_sec, 37)
2636         self.assertEqual(t.tm_yday, 366)    # "year 0" is a leap year
2637         self.assertEqual(t.tm_isdst, 0)
2638 
2639         huge = cls(MAXYEAR, 12, 31, 23, 59, 37, 999999, tzinfo=UOFS(-1439))
2640         # That goes forward 1 minute less than a full day.
2641         t = huge.utctimetuple()
2642         self.assertEqual(t.tm_year, MAXYEAR+1)
2643         self.assertEqual(t.tm_mon, 1)
2644         self.assertEqual(t.tm_mday, 1)
2645         self.assertEqual(t.tm_hour, 23)
2646         self.assertEqual(t.tm_min, 58)
2647         self.assertEqual(t.tm_sec, 37)
2648         self.assertEqual(t.tm_yday, 1)
2649         self.assertEqual(t.tm_isdst, 0)
2650 
2651     def test_tzinfo_isoformat(self):
2652         zero = FixedOffset(0, "+00:00")
2653         plus = FixedOffset(220, "+03:40")
2654         minus = FixedOffset(-231, "-03:51")
2655         unknown = FixedOffset(None, "")
2656 
2657         cls = self.theclass
2658         datestr = '0001-02-03'
2659         for ofs in None, zero, plus, minus, unknown:
2660             for us in 0, 987001:
2661                 d = cls(1, 2, 3, 4, 5, 59, us, tzinfo=ofs)
2662                 timestr = '04:05:59' + (us and '.987001' or '')
2663                 ofsstr = ofs is not None and d.tzname() or ''
2664                 tailstr = timestr + ofsstr
2665                 iso = d.isoformat()
2666                 self.assertEqual(iso, datestr + 'T' + tailstr)
2667                 self.assertEqual(iso, d.isoformat('T'))
2668                 self.assertEqual(d.isoformat('k'), datestr + 'k' + tailstr)
2669                 self.assertEqual(str(d), datestr + ' ' + tailstr)
2670 
2671     def test_replace(self):
2672         cls = self.theclass
2673         z100 = FixedOffset(100, "+100")
2674         zm200 = FixedOffset(timedelta(minutes=-200), "-200")
2675         args = [1, 2, 3, 4, 5, 6, 7, z100]
2676         base = cls(*args)
2677         self.assertEqual(base, base.replace())
2678 
2679         i = 0
2680         for name, newval in (("year", 2),
2681                              ("month", 3),
2682                              ("day", 4),
2683                              ("hour", 5),
2684                              ("minute", 6),
2685                              ("second", 7),
2686                              ("microsecond", 8),
2687                              ("tzinfo", zm200)):
2688             newargs = args[:]
2689             newargs[i] = newval
2690             expected = cls(*newargs)
2691             got = base.replace(**{name: newval})
2692             self.assertEqual(expected, got)
2693             i += 1
2694 
2695         # Ensure we can get rid of a tzinfo.
2696         self.assertEqual(base.tzname(), "+100")
2697         base2 = base.replace(tzinfo=None)
2698         self.failUnless(base2.tzinfo is None)
2699         self.failUnless(base2.tzname() is None)
2700 
2701         # Ensure we can add one.
2702         base3 = base2.replace(tzinfo=z100)
2703         self.assertEqual(base, base3)
2704         self.failUnless(base.tzinfo is base3.tzinfo)
2705 
2706         # Out of bounds.
2707         base = cls(2000, 2, 29)
2708         self.assertRaises(ValueError, base.replace, year=2001)
2709 
2710     def test_more_astimezone(self):
2711         # The inherited test_astimezone covered some trivial and error cases.
2712         fnone = FixedOffset(None, "None")
2713         f44m = FixedOffset(44, "44")
2714         fm5h = FixedOffset(-timedelta(hours=5), "m300")
2715 
2716         dt = self.theclass.now(tz=f44m)
2717         self.failUnless(dt.tzinfo is f44m)
2718         # Replacing with degenerate tzinfo raises an exception.
2719         self.assertRaises(ValueError, dt.astimezone, fnone)
2720         # Ditto with None tz.
2721         self.assertRaises(TypeError, dt.astimezone, None)
2722         # Replacing with same tzinfo makes no change.
2723         x = dt.astimezone(dt.tzinfo)
2724         self.failUnless(x.tzinfo is f44m)
2725         self.assertEqual(x.date(), dt.date())
2726         self.assertEqual(x.time(), dt.time())
2727 
2728         # Replacing with different tzinfo does adjust.
2729         got = dt.astimezone(fm5h)
2730         self.failUnless(got.tzinfo is fm5h)
2731         self.assertEqual(got.utcoffset(), timedelta(hours=-5))
2732         expected = dt - dt.utcoffset()  # in effect, convert to UTC
2733         expected += fm5h.utcoffset(dt)  # and from there to local time
2734         expected = expected.replace(tzinfo=fm5h) # and attach new tzinfo
2735         self.assertEqual(got.date(), expected.date())
2736         self.assertEqual(got.time(), expected.time())
2737         self.assertEqual(got.timetz(), expected.timetz())
2738         self.failUnless(got.tzinfo is expected.tzinfo)
2739         self.assertEqual(got, expected)
2740 
2741     def test_aware_subtract(self):
2742         cls = self.theclass
2743 
2744         # Ensure that utcoffset() is ignored when the operands have the
2745         # same tzinfo member.
2746         class OperandDependentOffset(tzinfo):
2747             def utcoffset(self, t):
2748                 if t.minute < 10:
2749                     # d0 and d1 equal after adjustment
2750                     return timedelta(minutes=t.minute)
2751                 else:
2752                     # d2 off in the weeds
2753                     return timedelta(minutes=59)
2754 
2755         base = cls(8, 9, 10, 11, 12, 13, 14, tzinfo=OperandDependentOffset())
2756         d0 = base.replace(minute=3)
2757         d1 = base.replace(minute=9)
2758         d2 = base.replace(minute=11)
2759         for x in d0, d1, d2:
2760             for y in d0, d1, d2:
2761                 got = x - y
2762                 expected = timedelta(minutes=x.minute - y.minute)
2763                 self.assertEqual(got, expected)
2764 
2765         # OTOH, if the tzinfo members are distinct, utcoffsets aren't
2766         # ignored.
2767         base = cls(8, 9, 10, 11, 12, 13, 14)
2768         d0 = base.replace(minute=3, tzinfo=OperandDependentOffset())
2769         d1 = base.replace(minute=9, tzinfo=OperandDependentOffset())
2770         d2 = base.replace(minute=11, tzinfo=OperandDependentOffset())
2771         for x in d0, d1, d2:
2772             for y in d0, d1, d2:
2773                 got = x - y
2774                 if (x is d0 or x is d1) and (y is d0 or y is d1):
2775                     expected = timedelta(0)
2776                 elif x is y is d2:
2777                     expected = timedelta(0)
2778                 elif x is d2:
2779                     expected = timedelta(minutes=(11-59)-0)
2780                 else:
2781                     assert y is d2
2782                     expected = timedelta(minutes=0-(11-59))
2783                 self.assertEqual(got, expected)
2784 
2785     def test_mixed_compare(self):
2786         t1 = datetime(1, 2, 3, 4, 5, 6, 7)
2787         t2 = datetime(1, 2, 3, 4, 5, 6, 7)
2788         self.assertEqual(t1, t2)
2789         t2 = t2.replace(tzinfo=None)
2790         self.assertEqual(t1, t2)
2791         t2 = t2.replace(tzinfo=FixedOffset(None, ""))
2792         self.assertEqual(t1, t2)
2793         t2 = t2.replace(tzinfo=FixedOffset(0, ""))
2794         self.assertRaises(TypeError, lambda: t1 == t2)
2795 
2796         # In datetime w/ identical tzinfo objects, utcoffset is ignored.
2797         class Varies(tzinfo):
2798             def __init__(self):
2799                 self.offset = timedelta(minutes=22)
2800             def utcoffset(self, t):
2801                 self.offset += timedelta(minutes=1)
2802                 return self.offset
2803 
2804         v = Varies()
2805         t1 = t2.replace(tzinfo=v)
2806         t2 = t2.replace(tzinfo=v)
2807         self.assertEqual(t1.utcoffset(), timedelta(minutes=23))
2808         self.assertEqual(t2.utcoffset(), timedelta(minutes=24))
2809         self.assertEqual(t1, t2)
2810 
2811         # But if they're not identical, it isn't ignored.
2812         t2 = t2.replace(tzinfo=Varies())
2813         self.failUnless(t1 < t2)  # t1's offset counter still going up
2814 
2815     def test_subclass_datetimetz(self):
2816 
2817         class C(self.theclass):
2818             theAnswer = 42
2819 
2820             def __new__(cls, *args, **kws):
2821                 temp = kws.copy()
2822                 extra = temp.pop('extra')
2823                 result = self.theclass.__new__(cls, *args, **temp)
2824                 result.extra = extra
2825                 return result
2826 
2827             def newmeth(self, start):
2828                 return start + self.hour + self.year
2829 
2830         args = 2002, 12, 31, 4, 5, 6, 500, FixedOffset(-300, "EST", 1)
2831 
2832         dt1 = self.theclass(*args)
2833         dt2 = C(*args, **{'extra': 7})
2834 
2835         self.assertEqual(dt2.__class__, C)
2836         self.assertEqual(dt2.theAnswer, 42)
2837         self.assertEqual(dt2.extra, 7)
2838         self.assertEqual(dt1.utcoffset(), dt2.utcoffset())
2839         self.assertEqual(dt2.newmeth(-7), dt1.hour + dt1.year - 7)
2840 
2841 # Pain to set up DST-aware tzinfo classes.
2842 
2843 def first_sunday_on_or_after(dt):
2844     days_to_go = 6 - dt.weekday()
2845     if days_to_go:
2846         dt += timedelta(days_to_go)
2847     return dt
2848 
2849 ZERO = timedelta(0)
2850 HOUR = timedelta(hours=1)
2851 DAY = timedelta(days=1)
2852 # In the US, DST starts at 2am (standard time) on the first Sunday in April.
2853 DSTSTART = datetime(1, 4, 1, 2)
2854 # and ends at 2am (DST time; 1am standard time) on the last Sunday of Oct,
2855 # which is the first Sunday on or after Oct 25.  Because we view 1:MM as
2856 # being standard time on that day, there is no spelling in local time of
2857 # the last hour of DST (that's 1:MM DST, but 1:MM is taken as standard time).
2858 DSTEND = datetime(1, 10, 25, 1)
2859 
2860 class USTimeZone(tzinfo):
2861 
2862     def __init__(self, hours, reprname, stdname, dstname):
2863         self.stdoffset = timedelta(hours=hours)
2864         self.reprname = reprname
2865         self.stdname = stdname
2866         self.dstname = dstname
2867 
2868     def __repr__(self):
2869         return self.reprname
2870 
2871     def tzname(self, dt):
2872         if self.dst(dt):
2873             return self.dstname
2874         else:
2875             return self.stdname
2876 
2877     def utcoffset(self, dt):
2878         return self.stdoffset + self.dst(dt)
2879 
2880     def dst(self, dt):
2881         if dt is None or dt.tzinfo is None:
2882             # An exception instead may be sensible here, in one or more of
2883             # the cases.
2884             return ZERO
2885         assert dt.tzinfo is self
2886 
2887         # Find first Sunday in April.
2888         start = first_sunday_on_or_after(DSTSTART.replace(year=dt.year))
2889         assert start.weekday() == 6 and start.month == 4 and start.day <= 7
2890 
2891         # Find last Sunday in October.
2892         end = first_sunday_on_or_after(DSTEND.replace(year=dt.year))
2893         assert end.weekday() == 6 and end.month == 10 and end.day >= 25
2894 
2895         # Can't compare naive to aware objects, so strip the timezone from
2896         # dt first.
2897         if start <= dt.replace(tzinfo=None) < end:
2898             return HOUR
2899         else:
2900             return ZERO
2901 
2902 Eastern  = USTimeZone(-5, "Eastern",  "EST", "EDT")
2903 Central  = USTimeZone(-6, "Central",  "CST", "CDT")
2904 Mountain = USTimeZone(-7, "Mountain", "MST", "MDT")
2905 Pacific  = USTimeZone(-8, "Pacific",  "PST", "PDT")
2906 utc_real = FixedOffset(0, "UTC", 0)
2907 # For better test coverage, we want another flavor of UTC that's west of
2908 # the Eastern and Pacific timezones.
2909 utc_fake = FixedOffset(-12*60, "UTCfake", 0)
2910 
2911 class TestTimezoneConversions(unittest.TestCase):
2912     # The DST switch times for 2002, in std time.
2913     dston = datetime(2002, 4, 7, 2)
2914     dstoff = datetime(2002, 10, 27, 1)
2915 
2916     theclass = datetime
2917 
2918     # Check a time that's inside DST.
2919     def checkinside(self, dt, tz, utc, dston, dstoff):
2920         self.assertEqual(dt.dst(), HOUR)
2921 
2922         # Conversion to our own timezone is always an identity.
2923         self.assertEqual(dt.astimezone(tz), dt)
2924 
2925         asutc = dt.astimezone(utc)
2926         there_and_back = asutc.astimezone(tz)
2927 
2928         # Conversion to UTC and back isn't always an identity here,
2929         # because there are redundant spellings (in local time) of
2930         # UTC time when DST begins:  the clock jumps from 1:59:59
2931         # to 3:00:00, and a local time of 2:MM:SS doesn't really
2932         # make sense then.  The classes above treat 2:MM:SS as
2933         # daylight time then (it's "after 2am"), really an alias
2934         # for 1:MM:SS standard time.  The latter form is what
2935         # conversion back from UTC produces.
2936         if dt.date() == dston.date() and dt.hour == 2:
2937             # We're in the redundant hour, and coming back from
2938             # UTC gives the 1:MM:SS standard-time spelling.
2939             self.assertEqual(there_and_back + HOUR, dt)
2940             # Although during was considered to be in daylight
2941             # time, there_and_back is not.
2942             self.assertEqual(there_and_back.dst(), ZERO)
2943             # They're the same times in UTC.
2944             self.assertEqual(there_and_back.astimezone(utc),
2945                              dt.astimezone(utc))
2946         else:
2947             # We're not in the redundant hour.
2948             self.assertEqual(dt, there_and_back)
2949 
2950         # Because we have a redundant spelling when DST begins, there is
2951         # (unforunately) an hour when DST ends that can't be spelled at all in
2952         # local time.  When DST ends, the clock jumps from 1:59 back to 1:00
2953         # again.  The hour 1:MM DST has no spelling then:  1:MM is taken to be
2954         # standard time.  1:MM DST == 0:MM EST, but 0:MM is taken to be
2955         # daylight time.  The hour 1:MM daylight == 0:MM standard can't be
2956         # expressed in local time.  Nevertheless, we want conversion back
2957         # from UTC to mimic the local clock's "repeat an hour" behavior.
2958         nexthour_utc = asutc + HOUR
2959         nexthour_tz = nexthour_utc.astimezone(tz)
2960         if dt.date() == dstoff.date() and dt.hour == 0:
2961             # We're in the hour before the last DST hour.  The last DST hour
2962             # is ineffable.  We want the conversion back to repeat 1:MM.
2963             self.assertEqual(nexthour_tz, dt.replace(hour=1))
2964             nexthour_utc += HOUR
2965             nexthour_tz = nexthour_utc.astimezone(tz)
2966             self.assertEqual(nexthour_tz, dt.replace(hour=1))
2967         else:
2968             self.assertEqual(nexthour_tz - dt, HOUR)
2969 
2970     # Check a time that's outside DST.
2971     def checkoutside(self, dt, tz, utc):
2972         self.assertEqual(dt.dst(), ZERO)
2973 
2974         # Conversion to our own timezone is always an identity.
2975         self.assertEqual(dt.astimezone(tz), dt)
2976 
2977         # Converting to UTC and back is an identity too.
2978         asutc = dt.astimezone(utc)
2979         there_and_back = asutc.astimezone(tz)
2980         self.assertEqual(dt, there_and_back)
2981 
2982     def convert_between_tz_and_utc(self, tz, utc):
2983         dston = self.dston.replace(tzinfo=tz)
2984         # Because 1:MM on the day DST ends is taken as being standard time,
2985         # there is no spelling in tz for the last hour of daylight time.
2986         # For purposes of the test, the last hour of DST is 0:MM, which is
2987         # taken as being daylight time (and 1:MM is taken as being standard
2988         # time).
2989         dstoff = self.dstoff.replace(tzinfo=tz)
2990         for delta in (timedelta(weeks=13),
2991                       DAY,
2992                       HOUR,
2993                       timedelta(minutes=1),
2994                       timedelta(microseconds=1)):
2995 
2996             self.checkinside(dston, tz, utc, dston, dstoff)
2997             for during in dston + delta, dstoff - delta:
2998                 self.checkinside(during, tz, utc, dston, dstoff)
2999 
3000             self.checkoutside(dstoff, tz, utc)
3001             for outside in dston - delta, dstoff + delta:
3002                 self.checkoutside(outside, tz, utc)
3003 
3004     def test_easy(self):
3005         # Despite the name of this test, the endcases are excruciating.
3006         self.convert_between_tz_and_utc(Eastern, utc_real)
3007         self.convert_between_tz_and_utc(Pacific, utc_real)
3008         self.convert_between_tz_and_utc(Eastern, utc_fake)
3009         self.convert_between_tz_and_utc(Pacific, utc_fake)
3010         # The next is really dancing near the edge.  It works because
3011         # Pacific and Eastern are far enough apart that their "problem
3012         # hours" don't overlap.
3013         self.convert_between_tz_and_utc(Eastern, Pacific)
3014         self.convert_between_tz_and_utc(Pacific, Eastern)
3015         # OTOH, these fail!  Don't enable them.  The difficulty is that
3016         # the edge case tests assume that every hour is representable in
3017         # the "utc" class.  This is always true for a fixed-offset tzinfo
3018         # class (lke utc_real and utc_fake), but not for Eastern or Central.
3019         # For these adjacent DST-aware time zones, the range of time offsets
3020         # tested ends up creating hours in the one that aren't representable
3021         # in the other.  For the same reason, we would see failures in the
3022         # Eastern vs Pacific tests too if we added 3*HOUR to the list of
3023         # offset deltas in convert_between_tz_and_utc().
3024         #
3025         # self.convert_between_tz_and_utc(Eastern, Central)  # can't work
3026         # self.convert_between_tz_and_utc(Central, Eastern)  # can't work
3027 
3028     def test_tricky(self):
3029         # 22:00 on day before daylight starts.
3030         fourback = self.dston - timedelta(hours=4)
3031         ninewest = FixedOffset(-9*60, "-0900", 0)
3032         fourback = fourback.replace(tzinfo=ninewest)
3033         # 22:00-0900 is 7:00 UTC == 2:00 EST == 3:00 DST.  Since it's "after
3034         # 2", we should get the 3 spelling.
3035         # If we plug 22:00 the day before into Eastern, it "looks like std
3036         # time", so its offset is returned as -5, and -5 - -9 = 4.  Adding 4
3037         # to 22:00 lands on 2:00, which makes no sense in local time (the
3038         # local clock jumps from 1 to 3).  The point here is to make sure we
3039         # get the 3 spelling.
3040         expected = self.dston.replace(hour=3)
3041         got = fourback.astimezone(Eastern).replace(tzinfo=None)
3042         self.assertEqual(expected, got)
3043 
3044         # Similar, but map to 6:00 UTC == 1:00 EST == 2:00 DST.  In that
3045         # case we want the 1:00 spelling.
3046         sixutc = self.dston.replace(hour=6, tzinfo=utc_real)
3047         # Now 6:00 "looks like daylight", so the offset wrt Eastern is -4,
3048         # and adding -4-0 == -4 gives the 2:00 spelling.  We want the 1:00 EST
3049         # spelling.
3050         expected = self.dston.replace(hour=1)
3051         got = sixutc.astimezone(Eastern).replace(tzinfo=None)
3052         self.assertEqual(expected, got)
3053 
3054         # Now on the day DST ends, we want "repeat an hour" behavior.
3055         #  UTC  4:MM  5:MM  6:MM  7:MM  checking these
3056         #  EST 23:MM  0:MM  1:MM  2:MM
3057         #  EDT  0:MM  1:MM  2:MM  3:MM
3058         # wall  0:MM  1:MM  1:MM  2:MM  against these
3059         for utc in utc_real, utc_fake:
3060             for tz in Eastern, Pacific:
3061                 first_std_hour = self.dstoff - timedelta(hours=2) # 23:MM
3062                 # Convert that to UTC.
3063                 first_std_hour -= tz.utcoffset(None)
3064                 # Adjust for possibly fake UTC.
3065                 asutc = first_std_hour + utc.utcoffset(None)
3066                 # First UTC hour to convert; this is 4:00 when utc=utc_real &
3067                 # tz=Eastern.
3068                 asutcbase = asutc.replace(tzinfo=utc)
3069                 for tzhour in (0, 1, 1, 2):
3070                     expectedbase = self.dstoff.replace(hour=tzhour)
3071                     for minute in 0, 30, 59:
3072                         expected = expectedbase.replace(minute=minute)
3073                         asutc = asutcbase.replace(minute=minute)
3074                         astz = asutc.astimezone(tz)
3075                         self.assertEqual(astz.replace(tzinfo=None), expected)
3076                     asutcbase += HOUR
3077 
3078 
3079     def test_bogus_dst(self):
3080         class ok(tzinfo):
3081             def utcoffset(self, dt): return HOUR
3082             def dst(self, dt): return HOUR
3083 
3084         now = self.theclass.now().replace(tzinfo=utc_real)
3085         # Doesn't blow up.
3086         now.astimezone(ok())
3087 
3088         # Does blow up.
3089         class notok(ok):
3090             def dst(self, dt): return None
3091         self.assertRaises(ValueError, now.astimezone, notok())
3092 
3093     def test_fromutc(self):
3094         self.assertRaises(TypeError, Eastern.fromutc)   # not enough args
3095         now = datetime.utcnow().replace(tzinfo=utc_real)
3096         self.assertRaises(ValueError, Eastern.fromutc, now) # wrong tzinfo
3097         now = now.replace(tzinfo=Eastern)   # insert correct tzinfo
3098         enow = Eastern.fromutc(now)         # doesn't blow up
3099         self.assertEqual(enow.tzinfo, Eastern) # has right tzinfo member
3100         self.assertRaises(TypeError, Eastern.fromutc, now, now) # too many args
3101         self.assertRaises(TypeError, Eastern.fromutc, date.today()) # wrong type
3102 
3103         # Always converts UTC to standard time.
3104         class FauxUSTimeZone(USTimeZone):
3105             def fromutc(self, dt):
3106                 return dt + self.stdoffset
3107         FEastern  = FauxUSTimeZone(-5, "FEastern",  "FEST", "FEDT")
3108 
3109         #  UTC  4:MM  5:MM  6:MM  7:MM  8:MM  9:MM
3110         #  EST 23:MM  0:MM  1:MM  2:MM  3:MM  4:MM
3111         #  EDT  0:MM  1:MM  2:MM  3:MM  4:MM  5:MM
3112 
3113         # Check around DST start.
3114         start = self.dston.replace(hour=4, tzinfo=Eastern)
3115         fstart = start.replace(tzinfo=FEastern)
3116         for wall in 23, 0, 1, 3, 4, 5:
3117             expected = start.replace(hour=wall)
3118             if wall == 23:
3119                 expected -= timedelta(days=1)
3120             got = Eastern.fromutc(start)
3121             self.assertEqual(expected, got)
3122 
3123             expected = fstart + FEastern.stdoffset
3124             got = FEastern.fromutc(fstart)
3125             self.assertEqual(expected, got)
3126 
3127             # Ensure astimezone() calls fromutc() too.
3128             got = fstart.replace(tzinfo=utc_real).astimezone(FEastern)
3129             self.assertEqual(expected, got)
3130 
3131             start += HOUR
3132             fstart += HOUR
3133 
3134         # Check around DST end.
3135         start = self.dstoff.replace(hour=4, tzinfo=Eastern)
3136         fstart = start.replace(tzinfo=FEastern)
3137         for wall in 0, 1, 1, 2, 3, 4:
3138             expected = start.replace(hour=wall)
3139             got = Eastern.fromutc(start)
3140             self.assertEqual(expected, got)
3141 
3142             expected = fstart + FEastern.stdoffset
3143             got = FEastern.fromutc(fstart)
3144             self.assertEqual(expected, got)
3145 
3146             # Ensure astimezone() calls fromutc() too.
3147             got = fstart.replace(tzinfo=utc_real).astimezone(FEastern)
3148             self.assertEqual(expected, got)
3149 
3150             start += HOUR
3151             fstart += HOUR
3152 
3153 
3154 #############################################################################
3155 # oddballs
3156 
3157 class Oddballs(unittest.TestCase):
3158 
3159     def test_bug_1028306(self):
3160         # Trying to compare a date to a datetime should act like a mixed-
3161         # type comparison, despite that datetime is a subclass of date.
3162         as_date = date.today()
3163         as_datetime = datetime.combine(as_date, time())
3164         self.assert_(as_date != as_datetime)
3165         self.assert_(as_datetime != as_date)
3166         self.assert_(not as_date == as_datetime)
3167         self.assert_(not as_datetime == as_date)
3168         self.assertRaises(TypeError, lambda: as_date < as_datetime)
3169         self.assertRaises(TypeError, lambda: as_datetime < as_date)
3170         self.assertRaises(TypeError, lambda: as_date <= as_datetime)
3171         self.assertRaises(TypeError, lambda: as_datetime <= as_date)
3172         self.assertRaises(TypeError, lambda: as_date > as_datetime)
3173         self.assertRaises(TypeError, lambda: as_datetime > as_date)
3174         self.assertRaises(TypeError, lambda: as_date >= as_datetime)
3175         self.assertRaises(TypeError, lambda: as_datetime >= as_date)
3176 
3177         # Neverthelss, comparison should work with the base-class (date)
3178         # projection if use of a date method is forced.
3179         self.assert_(as_date.__eq__(as_datetime))
3180         different_day = (as_date.day + 1) % 20 + 1
3181         self.assert_(not as_date.__eq__(as_datetime.replace(day=
3182                                                      different_day)))
3183 
3184         # And date should compare with other subclasses of date.  If a
3185         # subclass wants to stop this, it's up to the subclass to do so.
3186         date_sc = SubclassDate(as_date.year, as_date.month, as_date.day)
3187         self.assertEqual(as_date, date_sc)
3188         self.assertEqual(date_sc, as_date)
3189 
3190         # Ditto for datetimes.
3191         datetime_sc = SubclassDatetime(as_datetime.year, as_datetime.month,
3192                                        as_date.day, 0, 0, 0)
3193         self.assertEqual(as_datetime, datetime_sc)
3194         self.assertEqual(datetime_sc, as_datetime)
3195 
3196 def test_suite():
3197     allsuites = [unittest.makeSuite(klass, 'test')
3198                  for klass in (TestModule,
3199                                TestTZInfo,
3200                                TestTimeDelta,
3201                                TestDateOnly,
3202                                TestDate,
3203                                TestDateTime,
3204                                TestTime,
3205                                TestTimeTZ,
3206                                TestDateTimeTZ,
3207                                TestTimezoneConversions,
3208                                Oddballs,
3209                               )
3210                 ]
3211     return unittest.TestSuite(allsuites)
3212 
3213 def test_main():
3214     import gc
3215     import sys
3216 
3217     thesuite = test_suite()
3218     lastrc = None
3219     while True:
3220         test_support.run_suite(thesuite)
3221         if 1:       # change to 0, under a debug build, for some leak detection
3222             break
3223         gc.collect()
3224         if gc.garbage:
3225             raise SystemError("gc.garbage not empty after test run: %r" %
3226                               gc.garbage)
3227         if hasattr(sys, 'gettotalrefcount'):
3228             thisrc = sys.gettotalrefcount()
3229             print >> sys.stderr, '*' * 10, 'total refs:', thisrc,
3230             if lastrc:
3231                 print >> sys.stderr, 'delta:', thisrc - lastrc
3232             else:
3233                 print >> sys.stderr
3234             lastrc = thisrc
3235 
3236 if __name__ == "__main__":
3237     test_main()
3238 

Generated by PyXR 0.9.4
SourceForge.net Logo