1ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh"""Test date/time type.
2ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehSee http://www.zope.org/Members/fdrake/DateTimeWiki/TestCases
4ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh"""
5ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom __future__ import division
6ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport sys
7ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport pickle
8ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport cPickle
9ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport unittest
10ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
11ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom test import test_support
12ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
13ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom datetime import MINYEAR, MAXYEAR
14ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom datetime import timedelta
15ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom datetime import tzinfo
16ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom datetime import time
17ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom datetime import date, datetime
18ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
19ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehpickle_choices = [(pickler, unpickler, proto)
20ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                  for pickler in pickle, cPickle
21ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                  for unpickler in pickle, cPickle
22ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                  for proto in range(3)]
23ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehassert len(pickle_choices) == 2*2*3
24ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
25ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# An arbitrary collection of objects of non-datetime types, for testing
26ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# mixed-type comparisons.
27ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehOTHERSTUFF = (10, 10L, 34.5, "abc", {}, [], ())
28ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
29ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
30ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh#############################################################################
31ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# module tests
32ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
33ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass TestModule(unittest.TestCase):
34ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
35ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_constants(self):
36ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        import datetime
37ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(datetime.MINYEAR, 1)
38ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(datetime.MAXYEAR, 9999)
39ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
40ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh#############################################################################
41ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# tzinfo tests
42ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
43ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass FixedOffset(tzinfo):
44ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def __init__(self, offset, name, dstoffset=42):
45ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if isinstance(offset, int):
46ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            offset = timedelta(minutes=offset)
47ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if isinstance(dstoffset, int):
48ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            dstoffset = timedelta(minutes=dstoffset)
49ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.__offset = offset
50ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.__name = name
51ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.__dstoffset = dstoffset
52ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def __repr__(self):
53ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return self.__name.lower()
54ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def utcoffset(self, dt):
55ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return self.__offset
56ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def tzname(self, dt):
57ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return self.__name
58ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def dst(self, dt):
59ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return self.__dstoffset
60ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
61ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass PicklableFixedOffset(FixedOffset):
62ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def __init__(self, offset=None, name=None, dstoffset=None):
63ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        FixedOffset.__init__(self, offset, name, dstoffset)
64ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
65ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass TestTZInfo(unittest.TestCase):
66ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
67ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_non_abstractness(self):
68ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # In order to allow subclasses to get pickled, the C implementation
69ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # wasn't able to get away with having __init__ raise
70ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # NotImplementedError.
71ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        useless = tzinfo()
72ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt = datetime.max
73ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(NotImplementedError, useless.tzname, dt)
74ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(NotImplementedError, useless.utcoffset, dt)
75ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(NotImplementedError, useless.dst, dt)
76ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
77ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_subclass_must_override(self):
78ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class NotEnough(tzinfo):
79ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def __init__(self, offset, name):
80ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.__offset = offset
81ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.__name = name
82ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(issubclass(NotEnough, tzinfo))
83ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ne = NotEnough(3, "NotByALongShot")
84ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertIsInstance(ne, tzinfo)
85ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
86ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt = datetime.now()
87ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(NotImplementedError, ne.tzname, dt)
88ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(NotImplementedError, ne.utcoffset, dt)
89ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(NotImplementedError, ne.dst, dt)
90ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
91ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_normal(self):
92ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        fo = FixedOffset(3, "Three")
93ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertIsInstance(fo, tzinfo)
94ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for dt in datetime.now(), None:
95ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(fo.utcoffset(dt), timedelta(minutes=3))
96ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(fo.tzname(dt), "Three")
97ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(fo.dst(dt), timedelta(minutes=42))
98ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
99ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_pickling_base(self):
100ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # There's no point to pickling tzinfo objects on their own (they
101ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # carry no data), but they need to be picklable anyway else
102ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # concrete subclasses can't be pickled.
103ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        orig = tzinfo.__new__(tzinfo)
104ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(type(orig) is tzinfo)
105ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for pickler, unpickler, proto in pickle_choices:
106ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            green = pickler.dumps(orig, proto)
107ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            derived = unpickler.loads(green)
108ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(type(derived) is tzinfo)
109ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
110ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_pickling_subclass(self):
111ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Make sure we can pickle/unpickle an instance of a subclass.
112ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        offset = timedelta(minutes=-300)
113ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        orig = PicklableFixedOffset(offset, 'cookie')
114ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertIsInstance(orig, tzinfo)
115ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(type(orig) is PicklableFixedOffset)
116ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(orig.utcoffset(None), offset)
117ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(orig.tzname(None), 'cookie')
118ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for pickler, unpickler, proto in pickle_choices:
119ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            green = pickler.dumps(orig, proto)
120ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            derived = unpickler.loads(green)
121ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertIsInstance(derived, tzinfo)
122ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(type(derived) is PicklableFixedOffset)
123ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(derived.utcoffset(None), offset)
124ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(derived.tzname(None), 'cookie')
125ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
126ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh#############################################################################
127ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# Base clase for testing a particular aspect of timedelta, time, date and
128ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# datetime comparisons.
129ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
130ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass HarmlessMixedComparison:
131ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Test that __eq__ and __ne__ don't complain for mixed-type comparisons.
132ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
133ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Subclasses must define 'theclass', and theclass(1, 1, 1) must be a
134ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # legit constructor.
135ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
136ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_harmless_mixed_comparison(self):
137ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        me = self.theclass(1, 1, 1)
138ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
139ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertFalse(me == ())
140ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(me != ())
141ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertFalse(() == me)
142ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(() != me)
143ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
144ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertIn(me, [1, 20L, [], me])
145ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertIn([], [me, 1, 20L, []])
146ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
147ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_harmful_mixed_comparison(self):
148ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        me = self.theclass(1, 1, 1)
149ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
150ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: me < ())
151ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: me <= ())
152ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: me > ())
153ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: me >= ())
154ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
155ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: () < me)
156ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: () <= me)
157ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: () > me)
158ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: () >= me)
159ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
160ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, cmp, (), me)
161ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, cmp, me, ())
162ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
163ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh#############################################################################
164ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# timedelta tests
165ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
166ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass TestTimeDelta(HarmlessMixedComparison, unittest.TestCase):
167ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
168ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    theclass = timedelta
169ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
170ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_constructor(self):
171ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq = self.assertEqual
172ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        td = timedelta
173ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
174ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Check keyword args to constructor
175ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(), td(weeks=0, days=0, hours=0, minutes=0, seconds=0,
176ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    milliseconds=0, microseconds=0))
177ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(1), td(days=1))
178ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(0, 1), td(seconds=1))
179ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(0, 0, 1), td(microseconds=1))
180ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(weeks=1), td(days=7))
181ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(days=1), td(hours=24))
182ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(hours=1), td(minutes=60))
183ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(minutes=1), td(seconds=60))
184ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(seconds=1), td(milliseconds=1000))
185ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(milliseconds=1), td(microseconds=1000))
186ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
187ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Check float args to constructor
188ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(weeks=1.0/7), td(days=1))
189ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(days=1.0/24), td(hours=1))
190ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(hours=1.0/60), td(minutes=1))
191ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(minutes=1.0/60), td(seconds=1))
192ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(seconds=0.001), td(milliseconds=1))
193ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(milliseconds=0.001), td(microseconds=1))
194ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
195ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_computations(self):
196ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq = self.assertEqual
197ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        td = timedelta
198ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
199ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        a = td(7) # One week
200ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        b = td(0, 60) # One minute
201ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        c = td(0, 0, 1000) # One millisecond
202ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(a+b+c, td(7, 60, 1000))
203ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(a-b, td(6, 24*3600 - 60))
204ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(-a, td(-7))
205ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(+a, td(7))
206ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(-b, td(-1, 24*3600 - 60))
207ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(-c, td(-1, 24*3600 - 1, 999000))
208ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(abs(a), a)
209ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(abs(-a), a)
210ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(6, 24*3600), a)
211ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(0, 0, 60*1000000), b)
212ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(a*10, td(70))
213ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(a*10, 10*a)
214ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(a*10L, 10*a)
215ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(b*10, td(0, 600))
216ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(10*b, td(0, 600))
217ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(b*10L, td(0, 600))
218ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(c*10, td(0, 0, 10000))
219ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(10*c, td(0, 0, 10000))
220ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(c*10L, td(0, 0, 10000))
221ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(a*-1, -a)
222ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(b*-2, -b-b)
223ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(c*-2, -c+-c)
224ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(b*(60*24), (b*60)*24)
225ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(b*(60*24), (60*b)*24)
226ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(c*1000, td(0, 1))
227ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(1000*c, td(0, 1))
228ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(a//7, td(1))
229ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(b//10, td(0, 6))
230ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(c//1000, td(0, 0, 1))
231ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(a//10, td(0, 7*24*360))
232ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(a//3600000, td(0, 0, 7*24*1000))
233ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
234ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Issue #11576
235ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(999999999, 86399, 999999) - td(999999999, 86399, 999998),
236ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh           td(0, 0, 1))
237ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(999999999, 1, 1) - td(999999999, 1, 0),
238ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh           td(0, 0, 1))
239ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
240ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
241ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_disallowed_computations(self):
242ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        a = timedelta(42)
243ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
244ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Add/sub ints, longs, floats should be illegal
245ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for i in 1, 1L, 1.0:
246ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: a+i)
247ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: a-i)
248ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: i+a)
249ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: i-a)
250ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
251ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Mul/div by float isn't supported.
252ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        x = 2.3
253ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: a*x)
254ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: x*a)
255ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: a/x)
256ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: x/a)
257ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: a // x)
258ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: x // a)
259ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
260ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Division of int by timedelta doesn't make sense.
261ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Division by zero doesn't make sense.
262ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for zero in 0, 0L:
263ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: zero // a)
264ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(ZeroDivisionError, lambda: a // zero)
265ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
266ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_basic_attributes(self):
267ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        days, seconds, us = 1, 7, 31
268ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        td = timedelta(days, seconds, us)
269ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(td.days, days)
270ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(td.seconds, seconds)
271ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(td.microseconds, us)
272ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
273ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_total_seconds(self):
274ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        td = timedelta(days=365)
275ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(td.total_seconds(), 31536000.0)
276ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for total_seconds in [123456.789012, -123456.789012, 0.123456, 0, 1e6]:
277ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            td = timedelta(seconds=total_seconds)
278ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(td.total_seconds(), total_seconds)
279ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Issue8644: Test that td.total_seconds() has the same
280ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # accuracy as td / timedelta(seconds=1).
281ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for ms in [-1, -2, -123]:
282ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            td = timedelta(microseconds=ms)
283ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(td.total_seconds(),
284ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             ((24*3600*td.days + td.seconds)*10**6
285ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                              + td.microseconds)/10**6)
286ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
287ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_carries(self):
288ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 = timedelta(days=100,
289ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                       weeks=-7,
290ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                       hours=-24*(100-49),
291ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                       minutes=-3,
292ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                       seconds=12,
293ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                       microseconds=(3*60 - 12) * 1e6 + 1)
294ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = timedelta(microseconds=1)
295ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1, t2)
296ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
297ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_hash_equality(self):
298ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 = timedelta(days=100,
299ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                       weeks=-7,
300ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                       hours=-24*(100-49),
301ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                       minutes=-3,
302ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                       seconds=12,
303ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                       microseconds=(3*60 - 12) * 1000000)
304ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = timedelta()
305ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(hash(t1), hash(t2))
306ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
307ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 += timedelta(weeks=7)
308ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 += timedelta(days=7*7)
309ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1, t2)
310ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(hash(t1), hash(t2))
311ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
312ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        d = {t1: 1}
313ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        d[t2] = 2
314ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(len(d), 1)
315ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(d[t1], 2)
316ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
317ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_pickling(self):
318ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        args = 12, 34, 56
319ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        orig = timedelta(*args)
320ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for pickler, unpickler, proto in pickle_choices:
321ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            green = pickler.dumps(orig, proto)
322ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            derived = unpickler.loads(green)
323ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(orig, derived)
324ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
325ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_compare(self):
326ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 = timedelta(2, 3, 4)
327ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = timedelta(2, 3, 4)
328ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t1 == t2)
329ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t1 <= t2)
330ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t1 >= t2)
331ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(not t1 != t2)
332ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(not t1 < t2)
333ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(not t1 > t2)
334ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(cmp(t1, t2), 0)
335ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(cmp(t2, t1), 0)
336ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
337ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for args in (3, 3, 3), (2, 4, 4), (2, 3, 5):
338ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            t2 = timedelta(*args)   # this is larger than t1
339ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t1 < t2)
340ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t2 > t1)
341ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t1 <= t2)
342ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t2 >= t1)
343ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t1 != t2)
344ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t2 != t1)
345ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(not t1 == t2)
346ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(not t2 == t1)
347ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(not t1 > t2)
348ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(not t2 < t1)
349ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(not t1 >= t2)
350ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(not t2 <= t1)
351ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(cmp(t1, t2), -1)
352ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(cmp(t2, t1), 1)
353ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
354ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for badarg in OTHERSTUFF:
355ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(t1 == badarg, False)
356ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(t1 != badarg, True)
357ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(badarg == t1, False)
358ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(badarg != t1, True)
359ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
360ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: t1 <= badarg)
361ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: t1 < badarg)
362ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: t1 > badarg)
363ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: t1 >= badarg)
364ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: badarg <= t1)
365ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: badarg < t1)
366ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: badarg > t1)
367ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: badarg >= t1)
368ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
369ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_str(self):
370ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        td = timedelta
371ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq = self.assertEqual
372ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
373ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(str(td(1)), "1 day, 0:00:00")
374ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(str(td(-1)), "-1 day, 0:00:00")
375ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(str(td(2)), "2 days, 0:00:00")
376ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(str(td(-2)), "-2 days, 0:00:00")
377ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
378ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(str(td(hours=12, minutes=58, seconds=59)), "12:58:59")
379ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(str(td(hours=2, minutes=3, seconds=4)), "2:03:04")
380ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(str(td(weeks=-30, hours=23, minutes=12, seconds=34)),
381ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh           "-210 days, 23:12:34")
382ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
383ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(str(td(milliseconds=1)), "0:00:00.001000")
384ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(str(td(microseconds=3)), "0:00:00.000003")
385ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
386ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(str(td(days=999999999, hours=23, minutes=59, seconds=59,
387ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                   microseconds=999999)),
388ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh           "999999999 days, 23:59:59.999999")
389ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
390ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_roundtrip(self):
391ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for td in (timedelta(days=999999999, hours=23, minutes=59,
392ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             seconds=59, microseconds=999999),
393ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                   timedelta(days=-999999999),
394ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                   timedelta(days=1, seconds=2, microseconds=3)):
395ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
396ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Verify td -> string -> td identity.
397ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            s = repr(td)
398ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(s.startswith('datetime.'))
399ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            s = s[9:]
400ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            td2 = eval(s)
401ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(td, td2)
402ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
403ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Verify identity via reconstructing from pieces.
404ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            td2 = timedelta(td.days, td.seconds, td.microseconds)
405ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(td, td2)
406ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
407ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_resolution_info(self):
408ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertIsInstance(timedelta.min, timedelta)
409ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertIsInstance(timedelta.max, timedelta)
410ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertIsInstance(timedelta.resolution, timedelta)
411ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(timedelta.max > timedelta.min)
412ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(timedelta.min, timedelta(-999999999))
413ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(timedelta.max, timedelta(999999999, 24*3600-1, 1e6-1))
414ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(timedelta.resolution, timedelta(0, 0, 1))
415ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
416ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_overflow(self):
417ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        tiny = timedelta.resolution
418ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
419ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        td = timedelta.min + tiny
420ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        td -= tiny  # no problem
421ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(OverflowError, td.__sub__, tiny)
422ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(OverflowError, td.__add__, -tiny)
423ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
424ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        td = timedelta.max - tiny
425ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        td += tiny  # no problem
426ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(OverflowError, td.__add__, tiny)
427ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(OverflowError, td.__sub__, -tiny)
428ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
429ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(OverflowError, lambda: -timedelta.max)
430ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
431ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_microsecond_rounding(self):
432ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        td = timedelta
433ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq = self.assertEqual
434ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
435ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Single-field rounding.
436ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(milliseconds=0.4/1000), td(0))    # rounds to 0
437ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(milliseconds=-0.4/1000), td(0))    # rounds to 0
438ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(milliseconds=0.6/1000), td(microseconds=1))
439ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(milliseconds=-0.6/1000), td(microseconds=-1))
440ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
441ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Rounding due to contributions from more than one field.
442ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        us_per_hour = 3600e6
443ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        us_per_day = us_per_hour * 24
444ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(days=.4/us_per_day), td(0))
445ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(hours=.2/us_per_hour), td(0))
446ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(days=.4/us_per_day, hours=.2/us_per_hour), td(microseconds=1))
447ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
448ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(days=-.4/us_per_day), td(0))
449ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(hours=-.2/us_per_hour), td(0))
450ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        eq(td(days=-.4/us_per_day, hours=-.2/us_per_hour), td(microseconds=-1))
451ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
452ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_massive_normalization(self):
453ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        td = timedelta(microseconds=-1)
454ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual((td.days, td.seconds, td.microseconds),
455ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                         (-1, 24*3600-1, 999999))
456ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
457ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_bool(self):
458ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(timedelta(1))
459ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(timedelta(0, 1))
460ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(timedelta(0, 0, 1))
461ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(timedelta(microseconds=1))
462ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(not timedelta(0))
463ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
464ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_subclass_timedelta(self):
465ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
466ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class T(timedelta):
467ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            @staticmethod
468ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def from_td(td):
469ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return T(td.days, td.seconds, td.microseconds)
470ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
471ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def as_hours(self):
472ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                sum = (self.days * 24 +
473ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                       self.seconds / 3600.0 +
474ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                       self.microseconds / 3600e6)
475ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return round(sum)
476ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
477ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 = T(days=1)
478ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(type(t1) is T)
479ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1.as_hours(), 24)
480ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
481ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = T(days=-1, seconds=-3600)
482ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(type(t2) is T)
483ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t2.as_hours(), -25)
484ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
485ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t3 = t1 + t2
486ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(type(t3) is timedelta)
487ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t4 = T.from_td(t3)
488ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(type(t4) is T)
489ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t3.days, t4.days)
490ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t3.seconds, t4.seconds)
491ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t3.microseconds, t4.microseconds)
492ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(str(t3), str(t4))
493ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t4.as_hours(), -1)
494ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
495ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh#############################################################################
496ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# date tests
497ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
498ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass TestDateOnly(unittest.TestCase):
499ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Tests here won't pass if also run on datetime objects, so don't
500ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # subclass this to test datetimes too.
501ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
502ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_delta_non_days_ignored(self):
503ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt = date(2000, 1, 2)
504ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        delta = timedelta(days=1, hours=2, minutes=3, seconds=4,
505ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                          microseconds=5)
506ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        days = timedelta(delta.days)
507ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(days, timedelta(1))
508ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
509ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt2 = dt + delta
510ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2, dt + days)
511ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
512ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt2 = delta + dt
513ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2, dt + days)
514ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
515ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt2 = dt - delta
516ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2, dt - days)
517ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
518ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        delta = -delta
519ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        days = timedelta(delta.days)
520ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(days, timedelta(-2))
521ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
522ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt2 = dt + delta
523ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2, dt + days)
524ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
525ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt2 = delta + dt
526ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2, dt + days)
527ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
528ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt2 = dt - delta
529ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2, dt - days)
530ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
531ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass SubclassDate(date):
532ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    sub_var = 1
533ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
534ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass TestDate(HarmlessMixedComparison, unittest.TestCase):
535ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Tests here should pass for both dates and datetimes, except for a
536ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # few tests that TestDateTime overrides.
537ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
538ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    theclass = date
539ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
540ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_basic_attributes(self):
541ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt = self.theclass(2002, 3, 1)
542ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.year, 2002)
543ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.month, 3)
544ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.day, 1)
545ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
546ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_roundtrip(self):
547ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for dt in (self.theclass(1, 2, 3),
548ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                   self.theclass.today()):
549ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Verify dt -> string -> date identity.
550ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            s = repr(dt)
551ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(s.startswith('datetime.'))
552ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            s = s[9:]
553ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            dt2 = eval(s)
554ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(dt, dt2)
555ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
556ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Verify identity via reconstructing from pieces.
557ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            dt2 = self.theclass(dt.year, dt.month, dt.day)
558ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(dt, dt2)
559ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
560ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_ordinal_conversions(self):
561ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Check some fixed values.
562ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for y, m, d, n in [(1, 1, 1, 1),      # calendar origin
563ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                           (1, 12, 31, 365),
564ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                           (2, 1, 1, 366),
565ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                           # first example from "Calendrical Calculations"
566ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                           (1945, 11, 12, 710347)]:
567ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            d = self.theclass(y, m, d)
568ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(n, d.toordinal())
569ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            fromord = self.theclass.fromordinal(n)
570ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(d, fromord)
571ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if hasattr(fromord, "hour"):
572ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # if we're checking something fancier than a date, verify
573ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # the extra fields have been zeroed out
574ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.assertEqual(fromord.hour, 0)
575ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.assertEqual(fromord.minute, 0)
576ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.assertEqual(fromord.second, 0)
577ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.assertEqual(fromord.microsecond, 0)
578ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
579ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Check first and last days of year spottily across the whole
580ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # range of years supported.
581ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for year in xrange(MINYEAR, MAXYEAR+1, 7):
582ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Verify (year, 1, 1) -> ordinal -> y, m, d is identity.
583ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            d = self.theclass(year, 1, 1)
584ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            n = d.toordinal()
585ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            d2 = self.theclass.fromordinal(n)
586ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(d, d2)
587ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Verify that moving back a day gets to the end of year-1.
588ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if year > 1:
589ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                d = self.theclass.fromordinal(n-1)
590ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                d2 = self.theclass(year-1, 12, 31)
591ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.assertEqual(d, d2)
592ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.assertEqual(d2.toordinal(), n-1)
593ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
594ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Test every day in a leap-year and a non-leap year.
595ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dim = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
596ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for year, isleap in (2000, True), (2002, False):
597ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            n = self.theclass(year, 1, 1).toordinal()
598ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            for month, maxday in zip(range(1, 13), dim):
599ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if month == 2 and isleap:
600ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    maxday += 1
601ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                for day in range(1, maxday+1):
602ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    d = self.theclass(year, month, day)
603ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    self.assertEqual(d.toordinal(), n)
604ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    self.assertEqual(d, self.theclass.fromordinal(n))
605ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    n += 1
606ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
607ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_extreme_ordinals(self):
608ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        a = self.theclass.min
609ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        a = self.theclass(a.year, a.month, a.day)  # get rid of time parts
610ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        aord = a.toordinal()
611ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        b = a.fromordinal(aord)
612ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a, b)
613ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
614ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, lambda: a.fromordinal(aord - 1))
615ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
616ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        b = a + timedelta(days=1)
617ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(b.toordinal(), aord + 1)
618ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(b, self.theclass.fromordinal(aord + 1))
619ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
620ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        a = self.theclass.max
621ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        a = self.theclass(a.year, a.month, a.day)  # get rid of time parts
622ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        aord = a.toordinal()
623ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        b = a.fromordinal(aord)
624ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a, b)
625ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
626ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, lambda: a.fromordinal(aord + 1))
627ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
628ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        b = a - timedelta(days=1)
629ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(b.toordinal(), aord - 1)
630ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(b, self.theclass.fromordinal(aord - 1))
631ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
632ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_bad_constructor_arguments(self):
633ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # bad years
634ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(MINYEAR, 1, 1)  # no exception
635ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(MAXYEAR, 1, 1)  # no exception
636ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, MINYEAR-1, 1, 1)
637ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, MAXYEAR+1, 1, 1)
638ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # bad months
639ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(2000, 1, 1)    # no exception
640ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(2000, 12, 1)   # no exception
641ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 2000, 0, 1)
642ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 2000, 13, 1)
643ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # bad days
644ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(2000, 2, 29)   # no exception
645ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(2004, 2, 29)   # no exception
646ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(2400, 2, 29)   # no exception
647ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 2000, 2, 30)
648ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 2001, 2, 29)
649ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 2100, 2, 29)
650ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 1900, 2, 29)
651ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 2000, 1, 0)
652ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 2000, 1, 32)
653ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
654ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_hash_equality(self):
655ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        d = self.theclass(2000, 12, 31)
656ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # same thing
657ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        e = self.theclass(2000, 12, 31)
658ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(d, e)
659ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(hash(d), hash(e))
660ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
661ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dic = {d: 1}
662ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dic[e] = 2
663ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(len(dic), 1)
664ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dic[d], 2)
665ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dic[e], 2)
666ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
667ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        d = self.theclass(2001,  1,  1)
668ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # same thing
669ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        e = self.theclass(2001,  1,  1)
670ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(d, e)
671ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(hash(d), hash(e))
672ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
673ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dic = {d: 1}
674ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dic[e] = 2
675ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(len(dic), 1)
676ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dic[d], 2)
677ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dic[e], 2)
678ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
679ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_computations(self):
680ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        a = self.theclass(2002, 1, 31)
681ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        b = self.theclass(1956, 1, 31)
682ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
683ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        diff = a-b
684ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(diff.days, 46*365 + len(range(1956, 2002, 4)))
685ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(diff.seconds, 0)
686ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(diff.microseconds, 0)
687ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
688ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        day = timedelta(1)
689ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        week = timedelta(7)
690ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        a = self.theclass(2002, 3, 2)
691ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a + day, self.theclass(2002, 3, 3))
692ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(day + a, self.theclass(2002, 3, 3))
693ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a - day, self.theclass(2002, 3, 1))
694ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(-day + a, self.theclass(2002, 3, 1))
695ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a + week, self.theclass(2002, 3, 9))
696ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a - week, self.theclass(2002, 2, 23))
697ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a + 52*week, self.theclass(2003, 3, 1))
698ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a - 52*week, self.theclass(2001, 3, 3))
699ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual((a + week) - a, week)
700ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual((a + day) - a, day)
701ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual((a - week) - a, -week)
702ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual((a - day) - a, -day)
703ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a - (a + week), -week)
704ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a - (a + day), -day)
705ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a - (a - week), week)
706ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a - (a - day), day)
707ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
708ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Add/sub ints, longs, floats should be illegal
709ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for i in 1, 1L, 1.0:
710ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: a+i)
711ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: a-i)
712ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: i+a)
713ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: i-a)
714ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
715ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # delta - date is senseless.
716ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: day - a)
717ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # mixing date and (delta or date) via * or // is senseless
718ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: day * a)
719ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: a * day)
720ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: day // a)
721ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: a // day)
722ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: a * a)
723ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: a // a)
724ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # date + date is senseless
725ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: a + a)
726ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
727ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_overflow(self):
728ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        tiny = self.theclass.resolution
729ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
730ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for delta in [tiny, timedelta(1), timedelta(2)]:
731ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            dt = self.theclass.min + delta
732ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            dt -= delta  # no problem
733ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(OverflowError, dt.__sub__, delta)
734ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(OverflowError, dt.__add__, -delta)
735ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
736ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            dt = self.theclass.max - delta
737ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            dt += delta  # no problem
738ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(OverflowError, dt.__add__, delta)
739ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(OverflowError, dt.__sub__, -delta)
740ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
741ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_fromtimestamp(self):
742ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        import time
743ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
744ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Try an arbitrary fixed value.
745ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        year, month, day = 1999, 9, 19
746ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ts = time.mktime((year, month, day, 0, 0, 0, 0, 0, -1))
747ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        d = self.theclass.fromtimestamp(ts)
748ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(d.year, year)
749ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(d.month, month)
750ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(d.day, day)
751ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
752ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_insane_fromtimestamp(self):
753ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # It's possible that some platform maps time_t to double,
754ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # and that this test will fail there.  This test should
755ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # exempt such platforms (provided they return reasonable
756ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # results!).
757ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for insane in -1e200, 1e200:
758ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(ValueError, self.theclass.fromtimestamp,
759ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                              insane)
760ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
761ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_today(self):
762ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        import time
763ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
764ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # We claim that today() is like fromtimestamp(time.time()), so
765ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # prove it.
766ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for dummy in range(3):
767ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            today = self.theclass.today()
768ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            ts = time.time()
769ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            todayagain = self.theclass.fromtimestamp(ts)
770ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if today == todayagain:
771ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                break
772ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # There are several legit reasons that could fail:
773ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # 1. It recently became midnight, between the today() and the
774ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            #    time() calls.
775ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # 2. The platform time() has such fine resolution that we'll
776ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            #    never get the same value twice.
777ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # 3. The platform time() has poor resolution, and we just
778ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            #    happened to call today() right before a resolution quantum
779ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            #    boundary.
780ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # 4. The system clock got fiddled between calls.
781ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # In any case, wait a little while and try again.
782ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            time.sleep(0.1)
783ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
784ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # It worked or it didn't.  If it didn't, assume it's reason #2, and
785ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # let the test pass if they're within half a second of each other.
786ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(today == todayagain or
787ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        abs(todayagain - today) < timedelta(seconds=0.5))
788ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
789ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_weekday(self):
790ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for i in range(7):
791ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # March 4, 2002 is a Monday
792ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(self.theclass(2002, 3, 4+i).weekday(), i)
793ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(self.theclass(2002, 3, 4+i).isoweekday(), i+1)
794ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # January 2, 1956 is a Monday
795ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(self.theclass(1956, 1, 2+i).weekday(), i)
796ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(self.theclass(1956, 1, 2+i).isoweekday(), i+1)
797ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
798ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_isocalendar(self):
799ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Check examples from
800ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
801ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for i in range(7):
802ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            d = self.theclass(2003, 12, 22+i)
803ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(d.isocalendar(), (2003, 52, i+1))
804ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            d = self.theclass(2003, 12, 29) + timedelta(i)
805ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(d.isocalendar(), (2004, 1, i+1))
806ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            d = self.theclass(2004, 1, 5+i)
807ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(d.isocalendar(), (2004, 2, i+1))
808ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            d = self.theclass(2009, 12, 21+i)
809ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(d.isocalendar(), (2009, 52, i+1))
810ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            d = self.theclass(2009, 12, 28) + timedelta(i)
811ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(d.isocalendar(), (2009, 53, i+1))
812ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            d = self.theclass(2010, 1, 4+i)
813ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(d.isocalendar(), (2010, 1, i+1))
814ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
815ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_iso_long_years(self):
816ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Calculate long ISO years and compare to table from
817ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
818ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ISO_LONG_YEARS_TABLE = """
819ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh              4   32   60   88
820ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh              9   37   65   93
821ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh             15   43   71   99
822ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh             20   48   76
823ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh             26   54   82
824ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
825ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            105  133  161  189
826ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            111  139  167  195
827ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            116  144  172
828ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            122  150  178
829ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            128  156  184
830ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
831ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            201  229  257  285
832ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            207  235  263  291
833ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            212  240  268  296
834ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            218  246  274
835ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            224  252  280
836ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
837ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            303  331  359  387
838ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            308  336  364  392
839ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            314  342  370  398
840ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            320  348  376
841ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            325  353  381
842ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
843ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        iso_long_years = map(int, ISO_LONG_YEARS_TABLE.split())
844ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        iso_long_years.sort()
845ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        L = []
846ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for i in range(400):
847ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            d = self.theclass(2000+i, 12, 31)
848ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            d1 = self.theclass(1600+i, 12, 31)
849ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(d.isocalendar()[1:], d1.isocalendar()[1:])
850ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if d.isocalendar()[1] == 53:
851ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                L.append(i)
852ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(L, iso_long_years)
853ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
854ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_isoformat(self):
855ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(2, 3, 2)
856ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.isoformat(), "0002-03-02")
857ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
858ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_ctime(self):
859ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(2002, 3, 2)
860ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.ctime(), "Sat Mar  2 00:00:00 2002")
861ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
862ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_strftime(self):
863ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(2005, 3, 2)
864ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.strftime("m:%m d:%d y:%y"), "m:03 d:02 y:05")
865ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.strftime(""), "") # SF bug #761337
866ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.strftime('x'*1000), 'x'*1000) # SF bug #1556784
867ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
868ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, t.strftime) # needs an arg
869ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, t.strftime, "one", "two") # too many args
870ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, t.strftime, 42) # arg wrong type
871ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
872ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # test that unicode input is allowed (issue 2782)
873ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.strftime(u"%m"), "03")
874ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
875ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # A naive object replaces %z and %Z w/ empty strings.
876ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.strftime("'%z' '%Z'"), "'' ''")
877ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
878ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #make sure that invalid format specifiers are handled correctly
879ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #self.assertRaises(ValueError, t.strftime, "%e")
880ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #self.assertRaises(ValueError, t.strftime, "%")
881ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #self.assertRaises(ValueError, t.strftime, "%#")
882ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
883ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #oh well, some systems just ignore those invalid ones.
884ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #at least, excercise them to make sure that no crashes
885ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #are generated
886ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for f in ["%e", "%", "%#"]:
887ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            try:
888ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                t.strftime(f)
889ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            except ValueError:
890ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                pass
891ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
892ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #check that this standard extension works
893ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t.strftime("%f")
894ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
895ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
896ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_format(self):
897ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt = self.theclass(2007, 9, 10)
898ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.__format__(''), str(dt))
899ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
900ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # check that a derived class's __str__() gets called
901ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class A(self.theclass):
902ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def __str__(self):
903ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return 'A'
904ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        a = A(2007, 9, 10)
905ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a.__format__(''), 'A')
906ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
907ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # check that a derived class's strftime gets called
908ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class B(self.theclass):
909ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def strftime(self, format_spec):
910ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return 'B'
911ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        b = B(2007, 9, 10)
912ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(b.__format__(''), str(dt))
913ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
914ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for fmt in ["m:%m d:%d y:%y",
915ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    "m:%m d:%d y:%y H:%H M:%M S:%S",
916ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    "%z %Z",
917ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    ]:
918ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(dt.__format__(fmt), dt.strftime(fmt))
919ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(a.__format__(fmt), dt.strftime(fmt))
920ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(b.__format__(fmt), 'B')
921ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
922ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_resolution_info(self):
923ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertIsInstance(self.theclass.min, self.theclass)
924ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertIsInstance(self.theclass.max, self.theclass)
925ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertIsInstance(self.theclass.resolution, timedelta)
926ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(self.theclass.max > self.theclass.min)
927ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
928ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_extreme_timedelta(self):
929ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        big = self.theclass.max - self.theclass.min
930ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # 3652058 days, 23 hours, 59 minutes, 59 seconds, 999999 microseconds
931ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        n = (big.days*24*3600 + big.seconds)*1000000 + big.microseconds
932ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # n == 315537897599999999 ~= 2**58.13
933ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        justasbig = timedelta(0, 0, n)
934ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(big, justasbig)
935ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(self.theclass.min + big, self.theclass.max)
936ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(self.theclass.max - big, self.theclass.min)
937ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
938ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_timetuple(self):
939ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for i in range(7):
940ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # January 2, 1956 is a Monday (0)
941ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            d = self.theclass(1956, 1, 2+i)
942ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            t = d.timetuple()
943ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(t, (1956, 1, 2+i, 0, 0, 0, i, 2+i, -1))
944ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # February 1, 1956 is a Wednesday (2)
945ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            d = self.theclass(1956, 2, 1+i)
946ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            t = d.timetuple()
947ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(t, (1956, 2, 1+i, 0, 0, 0, (2+i)%7, 32+i, -1))
948ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # March 1, 1956 is a Thursday (3), and is the 31+29+1 = 61st day
949ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # of the year.
950ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            d = self.theclass(1956, 3, 1+i)
951ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            t = d.timetuple()
952ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(t, (1956, 3, 1+i, 0, 0, 0, (3+i)%7, 61+i, -1))
953ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(t.tm_year, 1956)
954ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(t.tm_mon, 3)
955ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(t.tm_mday, 1+i)
956ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(t.tm_hour, 0)
957ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(t.tm_min, 0)
958ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(t.tm_sec, 0)
959ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(t.tm_wday, (3+i)%7)
960ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(t.tm_yday, 61+i)
961ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(t.tm_isdst, -1)
962ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
963ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_pickling(self):
964ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        args = 6, 7, 23
965ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        orig = self.theclass(*args)
966ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for pickler, unpickler, proto in pickle_choices:
967ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            green = pickler.dumps(orig, proto)
968ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            derived = unpickler.loads(green)
969ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(orig, derived)
970ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
971ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_compare(self):
972ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 = self.theclass(2, 3, 4)
973ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = self.theclass(2, 3, 4)
974ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t1 == t2)
975ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t1 <= t2)
976ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t1 >= t2)
977ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(not t1 != t2)
978ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(not t1 < t2)
979ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(not t1 > t2)
980ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(cmp(t1, t2), 0)
981ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(cmp(t2, t1), 0)
982ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
983ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for args in (3, 3, 3), (2, 4, 4), (2, 3, 5):
984ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            t2 = self.theclass(*args)   # this is larger than t1
985ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t1 < t2)
986ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t2 > t1)
987ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t1 <= t2)
988ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t2 >= t1)
989ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t1 != t2)
990ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t2 != t1)
991ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(not t1 == t2)
992ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(not t2 == t1)
993ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(not t1 > t2)
994ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(not t2 < t1)
995ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(not t1 >= t2)
996ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(not t2 <= t1)
997ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(cmp(t1, t2), -1)
998ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(cmp(t2, t1), 1)
999ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1000ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for badarg in OTHERSTUFF:
1001ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(t1 == badarg, False)
1002ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(t1 != badarg, True)
1003ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(badarg == t1, False)
1004ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(badarg != t1, True)
1005ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1006ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: t1 < badarg)
1007ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: t1 > badarg)
1008ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: t1 >= badarg)
1009ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: badarg <= t1)
1010ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: badarg < t1)
1011ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: badarg > t1)
1012ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: badarg >= t1)
1013ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1014ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_mixed_compare(self):
1015ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        our = self.theclass(2000, 4, 5)
1016ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, cmp, our, 1)
1017ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, cmp, 1, our)
1018ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1019ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class AnotherDateTimeClass(object):
1020ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def __cmp__(self, other):
1021ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # Return "equal" so calling this can't be confused with
1022ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # compare-by-address (which never says "equal" for distinct
1023ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # objects).
1024ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return 0
1025ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            __hash__ = None # Silence Py3k warning
1026ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1027ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # This still errors, because date and datetime comparison raise
1028ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # TypeError instead of NotImplemented when they don't know what to
1029ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # do, in order to stop comparison from falling back to the default
1030ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # compare-by-address.
1031ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        their = AnotherDateTimeClass()
1032ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, cmp, our, their)
1033ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Oops:  The next stab raises TypeError in the C implementation,
1034ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # but not in the Python implementation of datetime.  The difference
1035ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # is due to that the Python implementation defines __cmp__ but
1036ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # the C implementation defines tp_richcompare.  This is more pain
1037ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # to fix than it's worth, so commenting out the test.
1038ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # self.assertEqual(cmp(their, our), 0)
1039ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1040ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # But date and datetime comparison return NotImplemented instead if the
1041ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # other object has a timetuple attr.  This gives the other object a
1042ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # chance to do the comparison.
1043ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class Comparable(AnotherDateTimeClass):
1044ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def timetuple(self):
1045ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return ()
1046ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1047ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        their = Comparable()
1048ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(cmp(our, their), 0)
1049ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(cmp(their, our), 0)
1050ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(our == their)
1051ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(their == our)
1052ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1053ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_bool(self):
1054ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # All dates are considered true.
1055ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(self.theclass.min)
1056ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(self.theclass.max)
1057ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1058ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_strftime_out_of_range(self):
1059ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # For nasty technical reasons, we can't handle years before 1900.
1060ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        cls = self.theclass
1061ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(cls(1900, 1, 1).strftime("%Y"), "1900")
1062ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for y in 1, 49, 51, 99, 100, 1000, 1899:
1063ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(ValueError, cls(y, 1, 1).strftime, "%Y")
1064ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1065ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_replace(self):
1066ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        cls = self.theclass
1067ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        args = [1, 2, 3]
1068ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base = cls(*args)
1069ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(base, base.replace())
1070ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1071ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        i = 0
1072ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for name, newval in (("year", 2),
1073ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             ("month", 3),
1074ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             ("day", 4)):
1075ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            newargs = args[:]
1076ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            newargs[i] = newval
1077ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            expected = cls(*newargs)
1078ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            got = base.replace(**{name: newval})
1079ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(expected, got)
1080ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            i += 1
1081ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1082ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Out of bounds.
1083ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base = cls(2000, 2, 29)
1084ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, base.replace, year=2001)
1085ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1086ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_subclass_date(self):
1087ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1088ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class C(self.theclass):
1089ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            theAnswer = 42
1090ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1091ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def __new__(cls, *args, **kws):
1092ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                temp = kws.copy()
1093ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                extra = temp.pop('extra')
1094ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                result = self.theclass.__new__(cls, *args, **temp)
1095ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                result.extra = extra
1096ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return result
1097ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1098ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def newmeth(self, start):
1099ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return start + self.year + self.month
1100ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1101ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        args = 2003, 4, 14
1102ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1103ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt1 = self.theclass(*args)
1104ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt2 = C(*args, **{'extra': 7})
1105ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1106ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2.__class__, C)
1107ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2.theAnswer, 42)
1108ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2.extra, 7)
1109ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt1.toordinal(), dt2.toordinal())
1110ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2.newmeth(-7), dt1.year + dt1.month - 7)
1111ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1112ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_pickling_subclass_date(self):
1113ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1114ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        args = 6, 7, 23
1115ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        orig = SubclassDate(*args)
1116ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for pickler, unpickler, proto in pickle_choices:
1117ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            green = pickler.dumps(orig, proto)
1118ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            derived = unpickler.loads(green)
1119ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(orig, derived)
1120ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1121ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_backdoor_resistance(self):
1122ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # For fast unpickling, the constructor accepts a pickle string.
1123ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # This is a low-overhead backdoor.  A user can (by intent or
1124ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # mistake) pass a string directly, which (if it's the right length)
1125ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # will get treated like a pickle, and bypass the normal sanity
1126ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # checks in the constructor.  This can create insane objects.
1127ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # The constructor doesn't want to burn the time to validate all
1128ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # fields, but does check the month field.  This stops, e.g.,
1129ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # datetime.datetime('1995-03-25') from yielding an insane object.
1130ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base = '1995-03-25'
1131ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not issubclass(self.theclass, datetime):
1132ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            base = base[:4]
1133ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for month_byte in '9', chr(0), chr(13), '\xff':
1134ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, self.theclass,
1135ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                         base[:2] + month_byte + base[3:])
1136ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for ord_byte in range(1, 13):
1137ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # This shouldn't blow up because of the month byte alone.  If
1138ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # the implementation changes to do more-careful checking, it may
1139ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # blow up because other fields are insane.
1140ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.theclass(base[:2] + chr(ord_byte) + base[3:])
1141ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1142ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh#############################################################################
1143ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# datetime tests
1144ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1145ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass SubclassDatetime(datetime):
1146ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    sub_var = 1
1147ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1148ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass TestDateTime(TestDate):
1149ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1150ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    theclass = datetime
1151ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1152ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_basic_attributes(self):
1153ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt = self.theclass(2002, 3, 1, 12, 0)
1154ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.year, 2002)
1155ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.month, 3)
1156ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.day, 1)
1157ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.hour, 12)
1158ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.minute, 0)
1159ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.second, 0)
1160ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.microsecond, 0)
1161ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1162ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_basic_attributes_nonzero(self):
1163ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Make sure all attributes are non-zero so bugs in
1164ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # bit-shifting access show up.
1165ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt = self.theclass(2002, 3, 1, 12, 59, 59, 8000)
1166ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.year, 2002)
1167ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.month, 3)
1168ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.day, 1)
1169ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.hour, 12)
1170ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.minute, 59)
1171ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.second, 59)
1172ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.microsecond, 8000)
1173ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1174ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_roundtrip(self):
1175ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for dt in (self.theclass(1, 2, 3, 4, 5, 6, 7),
1176ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                   self.theclass.now()):
1177ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Verify dt -> string -> datetime identity.
1178ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            s = repr(dt)
1179ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(s.startswith('datetime.'))
1180ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            s = s[9:]
1181ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            dt2 = eval(s)
1182ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(dt, dt2)
1183ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1184ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Verify identity via reconstructing from pieces.
1185ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            dt2 = self.theclass(dt.year, dt.month, dt.day,
1186ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                dt.hour, dt.minute, dt.second,
1187ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                dt.microsecond)
1188ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(dt, dt2)
1189ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1190ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_isoformat(self):
1191ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(2, 3, 2, 4, 5, 1, 123)
1192ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.isoformat(),    "0002-03-02T04:05:01.000123")
1193ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.isoformat('T'), "0002-03-02T04:05:01.000123")
1194ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.isoformat(' '), "0002-03-02 04:05:01.000123")
1195ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.isoformat('\x00'), "0002-03-02\x0004:05:01.000123")
1196ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # str is ISO format with the separator forced to a blank.
1197ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(str(t), "0002-03-02 04:05:01.000123")
1198ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1199ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(2, 3, 2)
1200ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.isoformat(),    "0002-03-02T00:00:00")
1201ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.isoformat('T'), "0002-03-02T00:00:00")
1202ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.isoformat(' '), "0002-03-02 00:00:00")
1203ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # str is ISO format with the separator forced to a blank.
1204ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(str(t), "0002-03-02 00:00:00")
1205ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1206ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_format(self):
1207ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt = self.theclass(2007, 9, 10, 4, 5, 1, 123)
1208ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.__format__(''), str(dt))
1209ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1210ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # check that a derived class's __str__() gets called
1211ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class A(self.theclass):
1212ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def __str__(self):
1213ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return 'A'
1214ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        a = A(2007, 9, 10, 4, 5, 1, 123)
1215ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a.__format__(''), 'A')
1216ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1217ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # check that a derived class's strftime gets called
1218ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class B(self.theclass):
1219ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def strftime(self, format_spec):
1220ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return 'B'
1221ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        b = B(2007, 9, 10, 4, 5, 1, 123)
1222ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(b.__format__(''), str(dt))
1223ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1224ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for fmt in ["m:%m d:%d y:%y",
1225ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    "m:%m d:%d y:%y H:%H M:%M S:%S",
1226ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    "%z %Z",
1227ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    ]:
1228ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(dt.__format__(fmt), dt.strftime(fmt))
1229ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(a.__format__(fmt), dt.strftime(fmt))
1230ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(b.__format__(fmt), 'B')
1231ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1232ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_more_ctime(self):
1233ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Test fields that TestDate doesn't touch.
1234ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        import time
1235ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1236ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(2002, 3, 2, 18, 3, 5, 123)
1237ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.ctime(), "Sat Mar  2 18:03:05 2002")
1238ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Oops!  The next line fails on Win2K under MSVC 6, so it's commented
1239ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # out.  The difference is that t.ctime() produces " 2" for the day,
1240ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # but platform ctime() produces "02" for the day.  According to
1241ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # C99, t.ctime() is correct here.
1242ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # self.assertEqual(t.ctime(), time.ctime(time.mktime(t.timetuple())))
1243ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1244ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # So test a case where that difference doesn't matter.
1245ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(2002, 3, 22, 18, 3, 5, 123)
1246ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.ctime(), time.ctime(time.mktime(t.timetuple())))
1247ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1248ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_tz_independent_comparing(self):
1249ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt1 = self.theclass(2002, 3, 1, 9, 0, 0)
1250ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt2 = self.theclass(2002, 3, 1, 10, 0, 0)
1251ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt3 = self.theclass(2002, 3, 1, 9, 0, 0)
1252ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt1, dt3)
1253ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(dt2 > dt3)
1254ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1255ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Make sure comparison doesn't forget microseconds, and isn't done
1256ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # via comparing a float timestamp (an IEEE double doesn't have enough
1257ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # precision to span microsecond resolution across years 1 thru 9999,
1258ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # so comparing via timestamp necessarily calls some distinct values
1259ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # equal).
1260ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt1 = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999998)
1261ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        us = timedelta(microseconds=1)
1262ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt2 = dt1 + us
1263ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2 - dt1, us)
1264ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(dt1 < dt2)
1265ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1266ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_strftime_with_bad_tzname_replace(self):
1267ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # verify ok if tzinfo.tzname().replace() returns a non-string
1268ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class MyTzInfo(FixedOffset):
1269ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def tzname(self, dt):
1270ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                class MyStr(str):
1271ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    def replace(self, *args):
1272ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        return None
1273ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return MyStr('name')
1274ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(2005, 3, 2, 0, 0, 0, 0, MyTzInfo(3, 'name'))
1275ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, t.strftime, '%Z')
1276ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1277ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_bad_constructor_arguments(self):
1278ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # bad years
1279ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(MINYEAR, 1, 1)  # no exception
1280ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(MAXYEAR, 1, 1)  # no exception
1281ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, MINYEAR-1, 1, 1)
1282ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, MAXYEAR+1, 1, 1)
1283ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # bad months
1284ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(2000, 1, 1)    # no exception
1285ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(2000, 12, 1)   # no exception
1286ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 2000, 0, 1)
1287ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 2000, 13, 1)
1288ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # bad days
1289ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(2000, 2, 29)   # no exception
1290ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(2004, 2, 29)   # no exception
1291ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(2400, 2, 29)   # no exception
1292ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 2000, 2, 30)
1293ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 2001, 2, 29)
1294ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 2100, 2, 29)
1295ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 1900, 2, 29)
1296ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 2000, 1, 0)
1297ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 2000, 1, 32)
1298ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # bad hours
1299ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(2000, 1, 31, 0)    # no exception
1300ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(2000, 1, 31, 23)   # no exception
1301ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 2000, 1, 31, -1)
1302ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 24)
1303ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # bad minutes
1304ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(2000, 1, 31, 23, 0)    # no exception
1305ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(2000, 1, 31, 23, 59)   # no exception
1306ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 23, -1)
1307ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 23, 60)
1308ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # bad seconds
1309ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(2000, 1, 31, 23, 59, 0)    # no exception
1310ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(2000, 1, 31, 23, 59, 59)   # no exception
1311ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 23, 59, -1)
1312ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 2000, 1, 31, 23, 59, 60)
1313ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # bad microseconds
1314ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(2000, 1, 31, 23, 59, 59, 0)    # no exception
1315ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(2000, 1, 31, 23, 59, 59, 999999)   # no exception
1316ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass,
1317ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                          2000, 1, 31, 23, 59, 59, -1)
1318ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass,
1319ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                          2000, 1, 31, 23, 59, 59,
1320ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                          1000000)
1321ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1322ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_hash_equality(self):
1323ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        d = self.theclass(2000, 12, 31, 23, 30, 17)
1324ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        e = self.theclass(2000, 12, 31, 23, 30, 17)
1325ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(d, e)
1326ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(hash(d), hash(e))
1327ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1328ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dic = {d: 1}
1329ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dic[e] = 2
1330ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(len(dic), 1)
1331ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dic[d], 2)
1332ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dic[e], 2)
1333ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1334ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        d = self.theclass(2001,  1,  1,  0,  5, 17)
1335ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        e = self.theclass(2001,  1,  1,  0,  5, 17)
1336ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(d, e)
1337ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(hash(d), hash(e))
1338ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1339ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dic = {d: 1}
1340ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dic[e] = 2
1341ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(len(dic), 1)
1342ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dic[d], 2)
1343ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dic[e], 2)
1344ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1345ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_computations(self):
1346ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        a = self.theclass(2002, 1, 31)
1347ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        b = self.theclass(1956, 1, 31)
1348ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        diff = a-b
1349ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(diff.days, 46*365 + len(range(1956, 2002, 4)))
1350ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(diff.seconds, 0)
1351ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(diff.microseconds, 0)
1352ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        a = self.theclass(2002, 3, 2, 17, 6)
1353ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        millisec = timedelta(0, 0, 1000)
1354ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        hour = timedelta(0, 3600)
1355ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        day = timedelta(1)
1356ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        week = timedelta(7)
1357ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a + hour, self.theclass(2002, 3, 2, 18, 6))
1358ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(hour + a, self.theclass(2002, 3, 2, 18, 6))
1359ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a + 10*hour, self.theclass(2002, 3, 3, 3, 6))
1360ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a - hour, self.theclass(2002, 3, 2, 16, 6))
1361ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(-hour + a, self.theclass(2002, 3, 2, 16, 6))
1362ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a - hour, a + -hour)
1363ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a - 20*hour, self.theclass(2002, 3, 1, 21, 6))
1364ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a + day, self.theclass(2002, 3, 3, 17, 6))
1365ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a - day, self.theclass(2002, 3, 1, 17, 6))
1366ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a + week, self.theclass(2002, 3, 9, 17, 6))
1367ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a - week, self.theclass(2002, 2, 23, 17, 6))
1368ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a + 52*week, self.theclass(2003, 3, 1, 17, 6))
1369ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a - 52*week, self.theclass(2001, 3, 3, 17, 6))
1370ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual((a + week) - a, week)
1371ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual((a + day) - a, day)
1372ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual((a + hour) - a, hour)
1373ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual((a + millisec) - a, millisec)
1374ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual((a - week) - a, -week)
1375ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual((a - day) - a, -day)
1376ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual((a - hour) - a, -hour)
1377ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual((a - millisec) - a, -millisec)
1378ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a - (a + week), -week)
1379ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a - (a + day), -day)
1380ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a - (a + hour), -hour)
1381ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a - (a + millisec), -millisec)
1382ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a - (a - week), week)
1383ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a - (a - day), day)
1384ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a - (a - hour), hour)
1385ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a - (a - millisec), millisec)
1386ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a + (week + day + hour + millisec),
1387ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                         self.theclass(2002, 3, 10, 18, 6, 0, 1000))
1388ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a + (week + day + hour + millisec),
1389ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                         (((a + week) + day) + hour) + millisec)
1390ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a - (week + day + hour + millisec),
1391ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                         self.theclass(2002, 2, 22, 16, 5, 59, 999000))
1392ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a - (week + day + hour + millisec),
1393ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                         (((a - week) - day) - hour) - millisec)
1394ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Add/sub ints, longs, floats should be illegal
1395ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for i in 1, 1L, 1.0:
1396ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: a+i)
1397ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: a-i)
1398ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: i+a)
1399ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: i-a)
1400ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1401ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # delta - datetime is senseless.
1402ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: day - a)
1403ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # mixing datetime and (delta or datetime) via * or // is senseless
1404ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: day * a)
1405ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: a * day)
1406ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: day // a)
1407ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: a // day)
1408ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: a * a)
1409ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: a // a)
1410ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # datetime + datetime is senseless
1411ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: a + a)
1412ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1413ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_pickling(self):
1414ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        args = 6, 7, 23, 20, 59, 1, 64**2
1415ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        orig = self.theclass(*args)
1416ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for pickler, unpickler, proto in pickle_choices:
1417ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            green = pickler.dumps(orig, proto)
1418ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            derived = unpickler.loads(green)
1419ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(orig, derived)
1420ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1421ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_more_pickling(self):
1422ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        a = self.theclass(2003, 2, 7, 16, 48, 37, 444116)
1423ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        s = pickle.dumps(a)
1424ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        b = pickle.loads(s)
1425ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(b.year, 2003)
1426ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(b.month, 2)
1427ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(b.day, 7)
1428ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1429ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_pickling_subclass_datetime(self):
1430ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        args = 6, 7, 23, 20, 59, 1, 64**2
1431ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        orig = SubclassDatetime(*args)
1432ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for pickler, unpickler, proto in pickle_choices:
1433ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            green = pickler.dumps(orig, proto)
1434ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            derived = unpickler.loads(green)
1435ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(orig, derived)
1436ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1437ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_more_compare(self):
1438ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # The test_compare() inherited from TestDate covers the error cases.
1439ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # We just want to test lexicographic ordering on the members datetime
1440ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # has that date lacks.
1441ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        args = [2000, 11, 29, 20, 58, 16, 999998]
1442ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 = self.theclass(*args)
1443ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = self.theclass(*args)
1444ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t1 == t2)
1445ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t1 <= t2)
1446ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t1 >= t2)
1447ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(not t1 != t2)
1448ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(not t1 < t2)
1449ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(not t1 > t2)
1450ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(cmp(t1, t2), 0)
1451ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(cmp(t2, t1), 0)
1452ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1453ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for i in range(len(args)):
1454ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            newargs = args[:]
1455ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            newargs[i] = args[i] + 1
1456ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            t2 = self.theclass(*newargs)   # this is larger than t1
1457ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t1 < t2)
1458ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t2 > t1)
1459ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t1 <= t2)
1460ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t2 >= t1)
1461ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t1 != t2)
1462ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t2 != t1)
1463ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(not t1 == t2)
1464ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(not t2 == t1)
1465ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(not t1 > t2)
1466ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(not t2 < t1)
1467ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(not t1 >= t2)
1468ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(not t2 <= t1)
1469ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(cmp(t1, t2), -1)
1470ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(cmp(t2, t1), 1)
1471ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1472ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1473ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # A helper for timestamp constructor tests.
1474ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def verify_field_equality(self, expected, got):
1475ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(expected.tm_year, got.year)
1476ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(expected.tm_mon, got.month)
1477ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(expected.tm_mday, got.day)
1478ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(expected.tm_hour, got.hour)
1479ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(expected.tm_min, got.minute)
1480ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(expected.tm_sec, got.second)
1481ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1482ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_fromtimestamp(self):
1483ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        import time
1484ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1485ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ts = time.time()
1486ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        expected = time.localtime(ts)
1487ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        got = self.theclass.fromtimestamp(ts)
1488ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.verify_field_equality(expected, got)
1489ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1490ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_utcfromtimestamp(self):
1491ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        import time
1492ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1493ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ts = time.time()
1494ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        expected = time.gmtime(ts)
1495ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        got = self.theclass.utcfromtimestamp(ts)
1496ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.verify_field_equality(expected, got)
1497ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1498ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_microsecond_rounding(self):
1499ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Test whether fromtimestamp "rounds up" floats that are less
1500ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # than one microsecond smaller than an integer.
1501ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(self.theclass.fromtimestamp(0.9999999),
1502ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                         self.theclass.fromtimestamp(1))
1503ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1504ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_insane_fromtimestamp(self):
1505ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # It's possible that some platform maps time_t to double,
1506ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # and that this test will fail there.  This test should
1507ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # exempt such platforms (provided they return reasonable
1508ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # results!).
1509ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for insane in -1e200, 1e200:
1510ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(ValueError, self.theclass.fromtimestamp,
1511ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                              insane)
1512ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1513ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_insane_utcfromtimestamp(self):
1514ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # It's possible that some platform maps time_t to double,
1515ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # and that this test will fail there.  This test should
1516ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # exempt such platforms (provided they return reasonable
1517ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # results!).
1518ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for insane in -1e200, 1e200:
1519ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(ValueError, self.theclass.utcfromtimestamp,
1520ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                              insane)
1521ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    @unittest.skipIf(sys.platform == "win32", "Windows doesn't accept negative timestamps")
1522ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_negative_float_fromtimestamp(self):
1523ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # The result is tz-dependent; at least test that this doesn't
1524ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # fail (like it did before bug 1646728 was fixed).
1525ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass.fromtimestamp(-1.05)
1526ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1527ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    @unittest.skipIf(sys.platform == "win32", "Windows doesn't accept negative timestamps")
1528ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_negative_float_utcfromtimestamp(self):
1529ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        d = self.theclass.utcfromtimestamp(-1.05)
1530ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(d, self.theclass(1969, 12, 31, 23, 59, 58, 950000))
1531ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1532ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_utcnow(self):
1533ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        import time
1534ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1535ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Call it a success if utcnow() and utcfromtimestamp() are within
1536ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # a second of each other.
1537ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        tolerance = timedelta(seconds=1)
1538ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for dummy in range(3):
1539ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            from_now = self.theclass.utcnow()
1540ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            from_timestamp = self.theclass.utcfromtimestamp(time.time())
1541ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if abs(from_timestamp - from_now) <= tolerance:
1542ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                break
1543ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Else try again a few times.
1544ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(abs(from_timestamp - from_now) <= tolerance)
1545ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1546ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_strptime(self):
1547ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        import _strptime
1548ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1549ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        string = '2004-12-01 13:02:47.197'
1550ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        format = '%Y-%m-%d %H:%M:%S.%f'
1551ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        result, frac = _strptime._strptime(string, format)
1552ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        expected = self.theclass(*(result[0:6]+(frac,)))
1553ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        got = self.theclass.strptime(string, format)
1554ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(expected, got)
1555ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1556ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_more_timetuple(self):
1557ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # This tests fields beyond those tested by the TestDate.test_timetuple.
1558ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(2004, 12, 31, 6, 22, 33)
1559ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.timetuple(), (2004, 12, 31, 6, 22, 33, 4, 366, -1))
1560ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.timetuple(),
1561ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                         (t.year, t.month, t.day,
1562ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                          t.hour, t.minute, t.second,
1563ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                          t.weekday(),
1564ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                          t.toordinal() - date(t.year, 1, 1).toordinal() + 1,
1565ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                          -1))
1566ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        tt = t.timetuple()
1567ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(tt.tm_year, t.year)
1568ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(tt.tm_mon, t.month)
1569ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(tt.tm_mday, t.day)
1570ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(tt.tm_hour, t.hour)
1571ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(tt.tm_min, t.minute)
1572ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(tt.tm_sec, t.second)
1573ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(tt.tm_wday, t.weekday())
1574ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(tt.tm_yday, t.toordinal() -
1575ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                     date(t.year, 1, 1).toordinal() + 1)
1576ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(tt.tm_isdst, -1)
1577ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1578ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_more_strftime(self):
1579ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # This tests fields beyond those tested by the TestDate.test_strftime.
1580ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(2004, 12, 31, 6, 22, 33, 47)
1581ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.strftime("%m %d %y %f %S %M %H %j"),
1582ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                    "12 31 04 000047 33 22 06 366")
1583ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1584ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_extract(self):
1585ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt = self.theclass(2002, 3, 4, 18, 45, 3, 1234)
1586ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.date(), date(2002, 3, 4))
1587ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.time(), time(18, 45, 3, 1234))
1588ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1589ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_combine(self):
1590ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        d = date(2002, 3, 4)
1591ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = time(18, 45, 3, 1234)
1592ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        expected = self.theclass(2002, 3, 4, 18, 45, 3, 1234)
1593ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        combine = self.theclass.combine
1594ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt = combine(d, t)
1595ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt, expected)
1596ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1597ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt = combine(time=t, date=d)
1598ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt, expected)
1599ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1600ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(d, dt.date())
1601ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t, dt.time())
1602ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt, combine(dt.date(), dt.time()))
1603ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1604ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, combine) # need an arg
1605ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, combine, d) # need two args
1606ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, combine, t, d) # args reversed
1607ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, combine, d, t, 1) # too many args
1608ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, combine, "date", "time") # wrong types
1609ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1610ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_replace(self):
1611ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        cls = self.theclass
1612ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        args = [1, 2, 3, 4, 5, 6, 7]
1613ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base = cls(*args)
1614ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(base, base.replace())
1615ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1616ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        i = 0
1617ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for name, newval in (("year", 2),
1618ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             ("month", 3),
1619ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             ("day", 4),
1620ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             ("hour", 5),
1621ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             ("minute", 6),
1622ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             ("second", 7),
1623ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             ("microsecond", 8)):
1624ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            newargs = args[:]
1625ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            newargs[i] = newval
1626ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            expected = cls(*newargs)
1627ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            got = base.replace(**{name: newval})
1628ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(expected, got)
1629ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            i += 1
1630ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1631ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Out of bounds.
1632ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base = cls(2000, 2, 29)
1633ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, base.replace, year=2001)
1634ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1635ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_astimezone(self):
1636ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Pretty boring!  The TZ test is more interesting here.  astimezone()
1637ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # simply can't be applied to a naive object.
1638ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt = self.theclass.now()
1639ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        f = FixedOffset(44, "")
1640ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, dt.astimezone) # not enough args
1641ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, dt.astimezone, f, f) # too many args
1642ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, dt.astimezone, dt) # arg wrong type
1643ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, dt.astimezone, f) # naive
1644ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, dt.astimezone, tz=f)  # naive
1645ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1646ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class Bogus(tzinfo):
1647ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def utcoffset(self, dt): return None
1648ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def dst(self, dt): return timedelta(0)
1649ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        bog = Bogus()
1650ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, dt.astimezone, bog)   # naive
1651ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1652ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class AlsoBogus(tzinfo):
1653ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def utcoffset(self, dt): return timedelta(0)
1654ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def dst(self, dt): return None
1655ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        alsobog = AlsoBogus()
1656ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, dt.astimezone, alsobog) # also naive
1657ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1658ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_subclass_datetime(self):
1659ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1660ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class C(self.theclass):
1661ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            theAnswer = 42
1662ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1663ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def __new__(cls, *args, **kws):
1664ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                temp = kws.copy()
1665ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                extra = temp.pop('extra')
1666ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                result = self.theclass.__new__(cls, *args, **temp)
1667ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                result.extra = extra
1668ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return result
1669ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1670ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def newmeth(self, start):
1671ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return start + self.year + self.month + self.second
1672ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1673ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        args = 2003, 4, 14, 12, 13, 41
1674ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1675ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt1 = self.theclass(*args)
1676ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt2 = C(*args, **{'extra': 7})
1677ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1678ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2.__class__, C)
1679ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2.theAnswer, 42)
1680ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2.extra, 7)
1681ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt1.toordinal(), dt2.toordinal())
1682ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2.newmeth(-7), dt1.year + dt1.month +
1683ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                          dt1.second - 7)
1684ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1685ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass SubclassTime(time):
1686ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    sub_var = 1
1687ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1688ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass TestTime(HarmlessMixedComparison, unittest.TestCase):
1689ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1690ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    theclass = time
1691ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1692ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_basic_attributes(self):
1693ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(12, 0)
1694ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.hour, 12)
1695ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.minute, 0)
1696ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.second, 0)
1697ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.microsecond, 0)
1698ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1699ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_basic_attributes_nonzero(self):
1700ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Make sure all attributes are non-zero so bugs in
1701ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # bit-shifting access show up.
1702ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(12, 59, 59, 8000)
1703ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.hour, 12)
1704ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.minute, 59)
1705ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.second, 59)
1706ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.microsecond, 8000)
1707ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1708ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_roundtrip(self):
1709ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(1, 2, 3, 4)
1710ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1711ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Verify t -> string -> time identity.
1712ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        s = repr(t)
1713ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(s.startswith('datetime.'))
1714ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        s = s[9:]
1715ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = eval(s)
1716ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t, t2)
1717ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1718ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Verify identity via reconstructing from pieces.
1719ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = self.theclass(t.hour, t.minute, t.second,
1720ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                           t.microsecond)
1721ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t, t2)
1722ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1723ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_comparing(self):
1724ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        args = [1, 2, 3, 4]
1725ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 = self.theclass(*args)
1726ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = self.theclass(*args)
1727ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t1 == t2)
1728ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t1 <= t2)
1729ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t1 >= t2)
1730ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(not t1 != t2)
1731ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(not t1 < t2)
1732ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(not t1 > t2)
1733ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(cmp(t1, t2), 0)
1734ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(cmp(t2, t1), 0)
1735ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1736ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for i in range(len(args)):
1737ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            newargs = args[:]
1738ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            newargs[i] = args[i] + 1
1739ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            t2 = self.theclass(*newargs)   # this is larger than t1
1740ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t1 < t2)
1741ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t2 > t1)
1742ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t1 <= t2)
1743ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t2 >= t1)
1744ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t1 != t2)
1745ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t2 != t1)
1746ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(not t1 == t2)
1747ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(not t2 == t1)
1748ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(not t1 > t2)
1749ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(not t2 < t1)
1750ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(not t1 >= t2)
1751ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(not t2 <= t1)
1752ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(cmp(t1, t2), -1)
1753ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(cmp(t2, t1), 1)
1754ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1755ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for badarg in OTHERSTUFF:
1756ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(t1 == badarg, False)
1757ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(t1 != badarg, True)
1758ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(badarg == t1, False)
1759ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(badarg != t1, True)
1760ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1761ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: t1 <= badarg)
1762ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: t1 < badarg)
1763ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: t1 > badarg)
1764ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: t1 >= badarg)
1765ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: badarg <= t1)
1766ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: badarg < t1)
1767ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: badarg > t1)
1768ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, lambda: badarg >= t1)
1769ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1770ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_bad_constructor_arguments(self):
1771ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # bad hours
1772ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(0, 0)    # no exception
1773ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(23, 0)   # no exception
1774ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, -1, 0)
1775ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 24, 0)
1776ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # bad minutes
1777ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(23, 0)    # no exception
1778ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(23, 59)   # no exception
1779ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 23, -1)
1780ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 23, 60)
1781ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # bad seconds
1782ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(23, 59, 0)    # no exception
1783ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(23, 59, 59)   # no exception
1784ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 23, 59, -1)
1785ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 23, 59, 60)
1786ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # bad microseconds
1787ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(23, 59, 59, 0)        # no exception
1788ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.theclass(23, 59, 59, 999999)   # no exception
1789ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 23, 59, 59, -1)
1790ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, self.theclass, 23, 59, 59, 1000000)
1791ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1792ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_hash_equality(self):
1793ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        d = self.theclass(23, 30, 17)
1794ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        e = self.theclass(23, 30, 17)
1795ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(d, e)
1796ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(hash(d), hash(e))
1797ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1798ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dic = {d: 1}
1799ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dic[e] = 2
1800ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(len(dic), 1)
1801ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dic[d], 2)
1802ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dic[e], 2)
1803ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1804ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        d = self.theclass(0,  5, 17)
1805ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        e = self.theclass(0,  5, 17)
1806ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(d, e)
1807ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(hash(d), hash(e))
1808ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1809ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dic = {d: 1}
1810ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dic[e] = 2
1811ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(len(dic), 1)
1812ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dic[d], 2)
1813ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dic[e], 2)
1814ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1815ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_isoformat(self):
1816ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(4, 5, 1, 123)
1817ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.isoformat(), "04:05:01.000123")
1818ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.isoformat(), str(t))
1819ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1820ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass()
1821ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.isoformat(), "00:00:00")
1822ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.isoformat(), str(t))
1823ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1824ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(microsecond=1)
1825ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.isoformat(), "00:00:00.000001")
1826ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.isoformat(), str(t))
1827ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1828ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(microsecond=10)
1829ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.isoformat(), "00:00:00.000010")
1830ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.isoformat(), str(t))
1831ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1832ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(microsecond=100)
1833ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.isoformat(), "00:00:00.000100")
1834ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.isoformat(), str(t))
1835ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1836ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(microsecond=1000)
1837ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.isoformat(), "00:00:00.001000")
1838ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.isoformat(), str(t))
1839ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1840ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(microsecond=10000)
1841ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.isoformat(), "00:00:00.010000")
1842ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.isoformat(), str(t))
1843ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1844ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(microsecond=100000)
1845ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.isoformat(), "00:00:00.100000")
1846ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.isoformat(), str(t))
1847ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1848ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_1653736(self):
1849ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # verify it doesn't accept extra keyword arguments
1850ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(second=1)
1851ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, t.isoformat, foo=3)
1852ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1853ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_strftime(self):
1854ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(1, 2, 3, 4)
1855ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.strftime('%H %M %S %f'), "01 02 03 000004")
1856ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # A naive object replaces %z and %Z with empty strings.
1857ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.strftime("'%z' '%Z'"), "'' ''")
1858ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1859ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_format(self):
1860ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(1, 2, 3, 4)
1861ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.__format__(''), str(t))
1862ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1863ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # check that a derived class's __str__() gets called
1864ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class A(self.theclass):
1865ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def __str__(self):
1866ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return 'A'
1867ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        a = A(1, 2, 3, 4)
1868ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(a.__format__(''), 'A')
1869ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1870ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # check that a derived class's strftime gets called
1871ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class B(self.theclass):
1872ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def strftime(self, format_spec):
1873ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return 'B'
1874ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        b = B(1, 2, 3, 4)
1875ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(b.__format__(''), str(t))
1876ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1877ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for fmt in ['%H %M %S',
1878ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    ]:
1879ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(t.__format__(fmt), t.strftime(fmt))
1880ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(a.__format__(fmt), t.strftime(fmt))
1881ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(b.__format__(fmt), 'B')
1882ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1883ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_str(self):
1884ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(str(self.theclass(1, 2, 3, 4)), "01:02:03.000004")
1885ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(str(self.theclass(10, 2, 3, 4000)), "10:02:03.004000")
1886ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(str(self.theclass(0, 2, 3, 400000)), "00:02:03.400000")
1887ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(str(self.theclass(12, 2, 3, 0)), "12:02:03")
1888ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(str(self.theclass(23, 15, 0, 0)), "23:15:00")
1889ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1890ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_repr(self):
1891ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        name = 'datetime.' + self.theclass.__name__
1892ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(repr(self.theclass(1, 2, 3, 4)),
1893ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                         "%s(1, 2, 3, 4)" % name)
1894ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(repr(self.theclass(10, 2, 3, 4000)),
1895ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                         "%s(10, 2, 3, 4000)" % name)
1896ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(repr(self.theclass(0, 2, 3, 400000)),
1897ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                         "%s(0, 2, 3, 400000)" % name)
1898ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(repr(self.theclass(12, 2, 3, 0)),
1899ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                         "%s(12, 2, 3)" % name)
1900ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(repr(self.theclass(23, 15, 0, 0)),
1901ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                         "%s(23, 15)" % name)
1902ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1903ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_resolution_info(self):
1904ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertIsInstance(self.theclass.min, self.theclass)
1905ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertIsInstance(self.theclass.max, self.theclass)
1906ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertIsInstance(self.theclass.resolution, timedelta)
1907ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(self.theclass.max > self.theclass.min)
1908ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1909ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_pickling(self):
1910ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        args = 20, 59, 16, 64**2
1911ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        orig = self.theclass(*args)
1912ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for pickler, unpickler, proto in pickle_choices:
1913ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            green = pickler.dumps(orig, proto)
1914ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            derived = unpickler.loads(green)
1915ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(orig, derived)
1916ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1917ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_pickling_subclass_time(self):
1918ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        args = 20, 59, 16, 64**2
1919ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        orig = SubclassTime(*args)
1920ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for pickler, unpickler, proto in pickle_choices:
1921ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            green = pickler.dumps(orig, proto)
1922ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            derived = unpickler.loads(green)
1923ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(orig, derived)
1924ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1925ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_bool(self):
1926ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        cls = self.theclass
1927ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(cls(1))
1928ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(cls(0, 1))
1929ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(cls(0, 0, 1))
1930ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(cls(0, 0, 0, 1))
1931ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(not cls(0))
1932ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(not cls())
1933ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1934ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_replace(self):
1935ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        cls = self.theclass
1936ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        args = [1, 2, 3, 4]
1937ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base = cls(*args)
1938ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(base, base.replace())
1939ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1940ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        i = 0
1941ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for name, newval in (("hour", 5),
1942ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             ("minute", 6),
1943ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             ("second", 7),
1944ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             ("microsecond", 8)):
1945ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            newargs = args[:]
1946ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            newargs[i] = newval
1947ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            expected = cls(*newargs)
1948ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            got = base.replace(**{name: newval})
1949ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(expected, got)
1950ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            i += 1
1951ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1952ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Out of bounds.
1953ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base = cls(1)
1954ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, base.replace, hour=24)
1955ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, base.replace, minute=-1)
1956ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, base.replace, second=100)
1957ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, base.replace, microsecond=1000000)
1958ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1959ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_subclass_time(self):
1960ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1961ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class C(self.theclass):
1962ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            theAnswer = 42
1963ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1964ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def __new__(cls, *args, **kws):
1965ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                temp = kws.copy()
1966ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                extra = temp.pop('extra')
1967ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                result = self.theclass.__new__(cls, *args, **temp)
1968ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                result.extra = extra
1969ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return result
1970ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1971ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def newmeth(self, start):
1972ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return start + self.hour + self.second
1973ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1974ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        args = 4, 5, 6
1975ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1976ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt1 = self.theclass(*args)
1977ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt2 = C(*args, **{'extra': 7})
1978ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1979ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2.__class__, C)
1980ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2.theAnswer, 42)
1981ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2.extra, 7)
1982ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt1.isoformat(), dt2.isoformat())
1983ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2.newmeth(-7), dt1.hour + dt1.second - 7)
1984ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1985ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_backdoor_resistance(self):
1986ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # see TestDate.test_backdoor_resistance().
1987ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base = '2:59.0'
1988ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for hour_byte in ' ', '9', chr(24), '\xff':
1989ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertRaises(TypeError, self.theclass,
1990ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                         hour_byte + base[1:])
1991ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1992ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# A mixin for classes with a tzinfo= argument.  Subclasses must define
1993ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# theclass as a class atribute, and theclass(1, 1, 1, tzinfo=whatever)
1994ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# must be legit (which is true for time and datetime).
1995ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass TZInfoBase:
1996ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
1997ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_argument_passing(self):
1998ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        cls = self.theclass
1999ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # A datetime passes itself on, a time passes None.
2000ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class introspective(tzinfo):
2001ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def tzname(self, dt):    return dt and "real" or "none"
2002ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def utcoffset(self, dt):
2003ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return timedelta(minutes = dt and 42 or -42)
2004ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            dst = utcoffset
2005ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2006ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        obj = cls(1, 2, 3, tzinfo=introspective())
2007ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2008ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        expected = cls is time and "none" or "real"
2009ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(obj.tzname(), expected)
2010ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2011ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        expected = timedelta(minutes=(cls is time and -42 or 42))
2012ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(obj.utcoffset(), expected)
2013ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(obj.dst(), expected)
2014ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2015ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_bad_tzinfo_classes(self):
2016ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        cls = self.theclass
2017ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, cls, 1, 1, 1, tzinfo=12)
2018ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2019ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class NiceTry(object):
2020ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def __init__(self): pass
2021ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def utcoffset(self, dt): pass
2022ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, cls, 1, 1, 1, tzinfo=NiceTry)
2023ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2024ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class BetterTry(tzinfo):
2025ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def __init__(self): pass
2026ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def utcoffset(self, dt): pass
2027ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        b = BetterTry()
2028ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = cls(1, 1, 1, tzinfo=b)
2029ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t.tzinfo is b)
2030ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2031ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_utc_offset_out_of_bounds(self):
2032ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class Edgy(tzinfo):
2033ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def __init__(self, offset):
2034ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.offset = timedelta(minutes=offset)
2035ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def utcoffset(self, dt):
2036ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return self.offset
2037ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2038ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        cls = self.theclass
2039ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for offset, legit in ((-1440, False),
2040ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                              (-1439, True),
2041ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                              (1439, True),
2042ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                              (1440, False)):
2043ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if cls is time:
2044ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                t = cls(1, 2, 3, tzinfo=Edgy(offset))
2045ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            elif cls is datetime:
2046ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                t = cls(6, 6, 6, 1, 2, 3, tzinfo=Edgy(offset))
2047ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            else:
2048ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                assert 0, "impossible"
2049ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if legit:
2050ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                aofs = abs(offset)
2051ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                h, m = divmod(aofs, 60)
2052ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                tag = "%c%02d:%02d" % (offset < 0 and '-' or '+', h, m)
2053ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if isinstance(t, datetime):
2054ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    t = t.timetz()
2055ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.assertEqual(str(t), "01:02:03" + tag)
2056ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            else:
2057ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.assertRaises(ValueError, str, t)
2058ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2059ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_tzinfo_classes(self):
2060ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        cls = self.theclass
2061ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class C1(tzinfo):
2062ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def utcoffset(self, dt): return None
2063ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def dst(self, dt): return None
2064ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def tzname(self, dt): return None
2065ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for t in (cls(1, 1, 1),
2066ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                  cls(1, 1, 1, tzinfo=None),
2067ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                  cls(1, 1, 1, tzinfo=C1())):
2068ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t.utcoffset() is None)
2069ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t.dst() is None)
2070ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(t.tzname() is None)
2071ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2072ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class C3(tzinfo):
2073ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def utcoffset(self, dt): return timedelta(minutes=-1439)
2074ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def dst(self, dt): return timedelta(minutes=1439)
2075ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def tzname(self, dt): return "aname"
2076ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = cls(1, 1, 1, tzinfo=C3())
2077ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.utcoffset(), timedelta(minutes=-1439))
2078ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.dst(), timedelta(minutes=1439))
2079ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.tzname(), "aname")
2080ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2081ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Wrong types.
2082ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class C4(tzinfo):
2083ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def utcoffset(self, dt): return "aname"
2084ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def dst(self, dt): return 7
2085ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def tzname(self, dt): return 0
2086ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = cls(1, 1, 1, tzinfo=C4())
2087ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, t.utcoffset)
2088ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, t.dst)
2089ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, t.tzname)
2090ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2091ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Offset out of range.
2092ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class C6(tzinfo):
2093ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def utcoffset(self, dt): return timedelta(hours=-24)
2094ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def dst(self, dt): return timedelta(hours=24)
2095ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = cls(1, 1, 1, tzinfo=C6())
2096ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, t.utcoffset)
2097ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, t.dst)
2098ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2099ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Not a whole number of minutes.
2100ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class C7(tzinfo):
2101ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def utcoffset(self, dt): return timedelta(seconds=61)
2102ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def dst(self, dt): return timedelta(microseconds=-81)
2103ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = cls(1, 1, 1, tzinfo=C7())
2104ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, t.utcoffset)
2105ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, t.dst)
2106ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2107ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_aware_compare(self):
2108ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        cls = self.theclass
2109ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2110ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Ensure that utcoffset() gets ignored if the comparands have
2111ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # the same tzinfo member.
2112ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class OperandDependentOffset(tzinfo):
2113ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def utcoffset(self, t):
2114ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if t.minute < 10:
2115ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    # d0 and d1 equal after adjustment
2116ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    return timedelta(minutes=t.minute)
2117ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                else:
2118ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    # d2 off in the weeds
2119ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    return timedelta(minutes=59)
2120ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2121ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base = cls(8, 9, 10, tzinfo=OperandDependentOffset())
2122ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        d0 = base.replace(minute=3)
2123ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        d1 = base.replace(minute=9)
2124ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        d2 = base.replace(minute=11)
2125ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for x in d0, d1, d2:
2126ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            for y in d0, d1, d2:
2127ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                got = cmp(x, y)
2128ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                expected = cmp(x.minute, y.minute)
2129ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.assertEqual(got, expected)
2130ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2131ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # However, if they're different members, uctoffset is not ignored.
2132ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Note that a time can't actually have an operand-depedent offset,
2133ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # though (and time.utcoffset() passes None to tzinfo.utcoffset()),
2134ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # so skip this test for time.
2135ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if cls is not time:
2136ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            d0 = base.replace(minute=3, tzinfo=OperandDependentOffset())
2137ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            d1 = base.replace(minute=9, tzinfo=OperandDependentOffset())
2138ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            d2 = base.replace(minute=11, tzinfo=OperandDependentOffset())
2139ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            for x in d0, d1, d2:
2140ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                for y in d0, d1, d2:
2141ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    got = cmp(x, y)
2142ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    if (x is d0 or x is d1) and (y is d0 or y is d1):
2143ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        expected = 0
2144ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    elif x is y is d2:
2145ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        expected = 0
2146ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    elif x is d2:
2147ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        expected = -1
2148ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    else:
2149ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        assert y is d2
2150ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        expected = 1
2151ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    self.assertEqual(got, expected)
2152ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2153ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2154ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# Testing time objects with a non-None tzinfo.
2155ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass TestTimeTZ(TestTime, TZInfoBase, unittest.TestCase):
2156ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    theclass = time
2157ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2158ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_empty(self):
2159ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass()
2160ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.hour, 0)
2161ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.minute, 0)
2162ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.second, 0)
2163ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.microsecond, 0)
2164ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t.tzinfo is None)
2165ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2166ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_zones(self):
2167ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        est = FixedOffset(-300, "EST", 1)
2168ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        utc = FixedOffset(0, "UTC", -2)
2169ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        met = FixedOffset(60, "MET", 3)
2170ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 = time( 7, 47, tzinfo=est)
2171ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = time(12, 47, tzinfo=utc)
2172ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t3 = time(13, 47, tzinfo=met)
2173ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t4 = time(microsecond=40)
2174ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t5 = time(microsecond=40, tzinfo=utc)
2175ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2176ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1.tzinfo, est)
2177ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t2.tzinfo, utc)
2178ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t3.tzinfo, met)
2179ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t4.tzinfo is None)
2180ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t5.tzinfo, utc)
2181ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2182ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1.utcoffset(), timedelta(minutes=-300))
2183ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t2.utcoffset(), timedelta(minutes=0))
2184ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t3.utcoffset(), timedelta(minutes=60))
2185ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t4.utcoffset() is None)
2186ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, t1.utcoffset, "no args")
2187ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2188ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1.tzname(), "EST")
2189ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t2.tzname(), "UTC")
2190ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t3.tzname(), "MET")
2191ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t4.tzname() is None)
2192ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, t1.tzname, "no args")
2193ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2194ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1.dst(), timedelta(minutes=1))
2195ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t2.dst(), timedelta(minutes=-2))
2196ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t3.dst(), timedelta(minutes=3))
2197ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t4.dst() is None)
2198ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, t1.dst, "no args")
2199ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2200ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(hash(t1), hash(t2))
2201ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(hash(t1), hash(t3))
2202ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(hash(t2), hash(t3))
2203ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2204ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1, t2)
2205ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1, t3)
2206ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t2, t3)
2207ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: t4 == t5) # mixed tz-aware & naive
2208ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: t4 < t5) # mixed tz-aware & naive
2209ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: t5 < t4) # mixed tz-aware & naive
2210ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2211ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(str(t1), "07:47:00-05:00")
2212ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(str(t2), "12:47:00+00:00")
2213ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(str(t3), "13:47:00+01:00")
2214ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(str(t4), "00:00:00.000040")
2215ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(str(t5), "00:00:00.000040+00:00")
2216ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2217ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1.isoformat(), "07:47:00-05:00")
2218ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t2.isoformat(), "12:47:00+00:00")
2219ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t3.isoformat(), "13:47:00+01:00")
2220ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t4.isoformat(), "00:00:00.000040")
2221ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t5.isoformat(), "00:00:00.000040+00:00")
2222ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2223ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        d = 'datetime.time'
2224ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(repr(t1), d + "(7, 47, tzinfo=est)")
2225ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(repr(t2), d + "(12, 47, tzinfo=utc)")
2226ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(repr(t3), d + "(13, 47, tzinfo=met)")
2227ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(repr(t4), d + "(0, 0, 0, 40)")
2228ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(repr(t5), d + "(0, 0, 0, 40, tzinfo=utc)")
2229ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2230ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1.strftime("%H:%M:%S %%Z=%Z %%z=%z"),
2231ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                     "07:47:00 %Z=EST %z=-0500")
2232ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t2.strftime("%H:%M:%S %Z %z"), "12:47:00 UTC +0000")
2233ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t3.strftime("%H:%M:%S %Z %z"), "13:47:00 MET +0100")
2234ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2235ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        yuck = FixedOffset(-1439, "%z %Z %%z%%Z")
2236ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 = time(23, 59, tzinfo=yuck)
2237ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1.strftime("%H:%M %%Z='%Z' %%z='%z'"),
2238ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                     "23:59 %Z='%z %Z %%z%%Z' %z='-2359'")
2239ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2240ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Check that an invalid tzname result raises an exception.
2241ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class Badtzname(tzinfo):
2242ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def tzname(self, dt): return 42
2243ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = time(2, 3, 4, tzinfo=Badtzname())
2244ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.strftime("%H:%M:%S"), "02:03:04")
2245ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, t.strftime, "%Z")
2246ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2247ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_hash_edge_cases(self):
2248ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Offsets that overflow a basic time.
2249ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 = self.theclass(0, 1, 2, 3, tzinfo=FixedOffset(1439, ""))
2250ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = self.theclass(0, 0, 2, 3, tzinfo=FixedOffset(1438, ""))
2251ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(hash(t1), hash(t2))
2252ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2253ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 = self.theclass(23, 58, 6, 100, tzinfo=FixedOffset(-1000, ""))
2254ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = self.theclass(23, 48, 6, 100, tzinfo=FixedOffset(-1010, ""))
2255ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(hash(t1), hash(t2))
2256ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2257ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_pickling(self):
2258ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Try one without a tzinfo.
2259ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        args = 20, 59, 16, 64**2
2260ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        orig = self.theclass(*args)
2261ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for pickler, unpickler, proto in pickle_choices:
2262ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            green = pickler.dumps(orig, proto)
2263ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            derived = unpickler.loads(green)
2264ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(orig, derived)
2265ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2266ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Try one with a tzinfo.
2267ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        tinfo = PicklableFixedOffset(-300, 'cookie')
2268ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        orig = self.theclass(5, 6, 7, tzinfo=tinfo)
2269ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for pickler, unpickler, proto in pickle_choices:
2270ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            green = pickler.dumps(orig, proto)
2271ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            derived = unpickler.loads(green)
2272ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(orig, derived)
2273ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertIsInstance(derived.tzinfo, PicklableFixedOffset)
2274ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(derived.utcoffset(), timedelta(minutes=-300))
2275ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(derived.tzname(), 'cookie')
2276ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2277ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_more_bool(self):
2278ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Test cases with non-None tzinfo.
2279ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        cls = self.theclass
2280ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2281ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = cls(0, tzinfo=FixedOffset(-300, ""))
2282ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t)
2283ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2284ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = cls(5, tzinfo=FixedOffset(-300, ""))
2285ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t)
2286ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2287ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = cls(5, tzinfo=FixedOffset(300, ""))
2288ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(not t)
2289ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2290ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = cls(23, 59, tzinfo=FixedOffset(23*60 + 59, ""))
2291ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(not t)
2292ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2293ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Mostly ensuring this doesn't overflow internally.
2294ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = cls(0, tzinfo=FixedOffset(23*60 + 59, ""))
2295ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t)
2296ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2297ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # But this should yield a value error -- the utcoffset is bogus.
2298ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = cls(0, tzinfo=FixedOffset(24*60, ""))
2299ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, lambda: bool(t))
2300ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2301ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Likewise.
2302ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = cls(0, tzinfo=FixedOffset(-24*60, ""))
2303ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, lambda: bool(t))
2304ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2305ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_replace(self):
2306ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        cls = self.theclass
2307ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        z100 = FixedOffset(100, "+100")
2308ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        zm200 = FixedOffset(timedelta(minutes=-200), "-200")
2309ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        args = [1, 2, 3, 4, z100]
2310ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base = cls(*args)
2311ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(base, base.replace())
2312ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2313ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        i = 0
2314ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for name, newval in (("hour", 5),
2315ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             ("minute", 6),
2316ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             ("second", 7),
2317ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             ("microsecond", 8),
2318ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             ("tzinfo", zm200)):
2319ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            newargs = args[:]
2320ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            newargs[i] = newval
2321ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            expected = cls(*newargs)
2322ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            got = base.replace(**{name: newval})
2323ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(expected, got)
2324ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            i += 1
2325ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2326ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Ensure we can get rid of a tzinfo.
2327ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(base.tzname(), "+100")
2328ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base2 = base.replace(tzinfo=None)
2329ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(base2.tzinfo is None)
2330ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(base2.tzname() is None)
2331ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2332ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Ensure we can add one.
2333ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base3 = base2.replace(tzinfo=z100)
2334ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(base, base3)
2335ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(base.tzinfo is base3.tzinfo)
2336ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2337ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Out of bounds.
2338ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base = cls(1)
2339ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, base.replace, hour=24)
2340ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, base.replace, minute=-1)
2341ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, base.replace, second=100)
2342ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, base.replace, microsecond=1000000)
2343ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2344ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_mixed_compare(self):
2345ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 = time(1, 2, 3)
2346ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = time(1, 2, 3)
2347ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1, t2)
2348ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = t2.replace(tzinfo=None)
2349ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1, t2)
2350ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = t2.replace(tzinfo=FixedOffset(None, ""))
2351ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1, t2)
2352ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = t2.replace(tzinfo=FixedOffset(0, ""))
2353ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: t1 == t2)
2354ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2355ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # In time w/ identical tzinfo objects, utcoffset is ignored.
2356ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class Varies(tzinfo):
2357ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def __init__(self):
2358ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.offset = timedelta(minutes=22)
2359ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def utcoffset(self, t):
2360ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.offset += timedelta(minutes=1)
2361ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return self.offset
2362ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2363ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        v = Varies()
2364ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 = t2.replace(tzinfo=v)
2365ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = t2.replace(tzinfo=v)
2366ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1.utcoffset(), timedelta(minutes=23))
2367ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t2.utcoffset(), timedelta(minutes=24))
2368ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1, t2)
2369ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2370ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # But if they're not identical, it isn't ignored.
2371ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = t2.replace(tzinfo=Varies())
2372ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t1 < t2)  # t1's offset counter still going up
2373ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2374ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_subclass_timetz(self):
2375ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2376ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class C(self.theclass):
2377ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            theAnswer = 42
2378ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2379ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def __new__(cls, *args, **kws):
2380ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                temp = kws.copy()
2381ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                extra = temp.pop('extra')
2382ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                result = self.theclass.__new__(cls, *args, **temp)
2383ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                result.extra = extra
2384ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return result
2385ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2386ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def newmeth(self, start):
2387ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return start + self.hour + self.second
2388ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2389ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        args = 4, 5, 6, 500, FixedOffset(-300, "EST", 1)
2390ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2391ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt1 = self.theclass(*args)
2392ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt2 = C(*args, **{'extra': 7})
2393ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2394ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2.__class__, C)
2395ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2.theAnswer, 42)
2396ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2.extra, 7)
2397ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt1.utcoffset(), dt2.utcoffset())
2398ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2.newmeth(-7), dt1.hour + dt1.second - 7)
2399ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2400ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2401ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# Testing datetime objects with a non-None tzinfo.
2402ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2403ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass TestDateTimeTZ(TestDateTime, TZInfoBase, unittest.TestCase):
2404ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    theclass = datetime
2405ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2406ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_trivial(self):
2407ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt = self.theclass(1, 2, 3, 4, 5, 6, 7)
2408ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.year, 1)
2409ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.month, 2)
2410ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.day, 3)
2411ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.hour, 4)
2412ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.minute, 5)
2413ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.second, 6)
2414ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.microsecond, 7)
2415ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.tzinfo, None)
2416ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2417ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_even_more_compare(self):
2418ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # The test_compare() and test_more_compare() inherited from TestDate
2419ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # and TestDateTime covered non-tzinfo cases.
2420ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2421ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Smallest possible after UTC adjustment.
2422ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 = self.theclass(1, 1, 1, tzinfo=FixedOffset(1439, ""))
2423ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Largest possible after UTC adjustment.
2424ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999999,
2425ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                           tzinfo=FixedOffset(-1439, ""))
2426ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2427ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Make sure those compare correctly, and w/o overflow.
2428ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t1 < t2)
2429ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t1 != t2)
2430ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t2 > t1)
2431ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2432ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t1 == t1)
2433ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t2 == t2)
2434ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2435ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Equal afer adjustment.
2436ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(1, ""))
2437ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = self.theclass(2, 1, 1, 3, 13, tzinfo=FixedOffset(3*60+13+2, ""))
2438ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1, t2)
2439ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2440ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Change t1 not to subtract a minute, and t1 should be larger.
2441ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(0, ""))
2442ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t1 > t2)
2443ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2444ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Change t1 to subtract 2 minutes, and t1 should be smaller.
2445ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(2, ""))
2446ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t1 < t2)
2447ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2448ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Back to the original t1, but make seconds resolve it.
2449ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(1, ""),
2450ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                           second=1)
2451ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t1 > t2)
2452ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2453ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Likewise, but make microseconds resolve it.
2454ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(1, ""),
2455ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                           microsecond=1)
2456ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t1 > t2)
2457ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2458ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Make t2 naive and it should fail.
2459ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = self.theclass.min
2460ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: t1 == t2)
2461ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t2, t2)
2462ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2463ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # It's also naive if it has tzinfo but tzinfo.utcoffset() is None.
2464ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class Naive(tzinfo):
2465ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def utcoffset(self, dt): return None
2466ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = self.theclass(5, 6, 7, tzinfo=Naive())
2467ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: t1 == t2)
2468ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t2, t2)
2469ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2470ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # OTOH, it's OK to compare two of these mixing the two ways of being
2471ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # naive.
2472ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 = self.theclass(5, 6, 7)
2473ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1, t2)
2474ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2475ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Try a bogus uctoffset.
2476ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class Bogus(tzinfo):
2477ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def utcoffset(self, dt):
2478ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return timedelta(minutes=1440) # out of bounds
2479ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 = self.theclass(2, 2, 2, tzinfo=Bogus())
2480ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = self.theclass(2, 2, 2, tzinfo=FixedOffset(0, ""))
2481ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, lambda: t1 == t2)
2482ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2483ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_pickling(self):
2484ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Try one without a tzinfo.
2485ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        args = 6, 7, 23, 20, 59, 1, 64**2
2486ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        orig = self.theclass(*args)
2487ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for pickler, unpickler, proto in pickle_choices:
2488ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            green = pickler.dumps(orig, proto)
2489ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            derived = unpickler.loads(green)
2490ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(orig, derived)
2491ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2492ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Try one with a tzinfo.
2493ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        tinfo = PicklableFixedOffset(-300, 'cookie')
2494ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        orig = self.theclass(*args, **{'tzinfo': tinfo})
2495ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        derived = self.theclass(1, 1, 1, tzinfo=FixedOffset(0, "", 0))
2496ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for pickler, unpickler, proto in pickle_choices:
2497ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            green = pickler.dumps(orig, proto)
2498ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            derived = unpickler.loads(green)
2499ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(orig, derived)
2500ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertIsInstance(derived.tzinfo, PicklableFixedOffset)
2501ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(derived.utcoffset(), timedelta(minutes=-300))
2502ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(derived.tzname(), 'cookie')
2503ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2504ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_extreme_hashes(self):
2505ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # If an attempt is made to hash these via subtracting the offset
2506ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # then hashing a datetime object, OverflowError results.  The
2507ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Python implementation used to blow up here.
2508ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(1, 1, 1, tzinfo=FixedOffset(1439, ""))
2509ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        hash(t)
2510ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999999,
2511ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                          tzinfo=FixedOffset(-1439, ""))
2512ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        hash(t)
2513ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2514ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # OTOH, an OOB offset should blow up.
2515ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = self.theclass(5, 5, 5, tzinfo=FixedOffset(-1440, ""))
2516ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, hash, t)
2517ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2518ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_zones(self):
2519ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        est = FixedOffset(-300, "EST")
2520ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        utc = FixedOffset(0, "UTC")
2521ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        met = FixedOffset(60, "MET")
2522ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 = datetime(2002, 3, 19,  7, 47, tzinfo=est)
2523ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = datetime(2002, 3, 19, 12, 47, tzinfo=utc)
2524ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t3 = datetime(2002, 3, 19, 13, 47, tzinfo=met)
2525ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1.tzinfo, est)
2526ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t2.tzinfo, utc)
2527ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t3.tzinfo, met)
2528ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1.utcoffset(), timedelta(minutes=-300))
2529ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t2.utcoffset(), timedelta(minutes=0))
2530ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t3.utcoffset(), timedelta(minutes=60))
2531ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1.tzname(), "EST")
2532ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t2.tzname(), "UTC")
2533ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t3.tzname(), "MET")
2534ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(hash(t1), hash(t2))
2535ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(hash(t1), hash(t3))
2536ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(hash(t2), hash(t3))
2537ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1, t2)
2538ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1, t3)
2539ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t2, t3)
2540ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(str(t1), "2002-03-19 07:47:00-05:00")
2541ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(str(t2), "2002-03-19 12:47:00+00:00")
2542ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(str(t3), "2002-03-19 13:47:00+01:00")
2543ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        d = 'datetime.datetime(2002, 3, 19, '
2544ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(repr(t1), d + "7, 47, tzinfo=est)")
2545ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(repr(t2), d + "12, 47, tzinfo=utc)")
2546ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(repr(t3), d + "13, 47, tzinfo=met)")
2547ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2548ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_combine(self):
2549ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        met = FixedOffset(60, "MET")
2550ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        d = date(2002, 3, 4)
2551ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        tz = time(18, 45, 3, 1234, tzinfo=met)
2552ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt = datetime.combine(d, tz)
2553ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt, datetime(2002, 3, 4, 18, 45, 3, 1234,
2554ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                        tzinfo=met))
2555ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2556ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_extract(self):
2557ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        met = FixedOffset(60, "MET")
2558ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt = self.theclass(2002, 3, 4, 18, 45, 3, 1234, tzinfo=met)
2559ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.date(), date(2002, 3, 4))
2560ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.time(), time(18, 45, 3, 1234))
2561ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.timetz(), time(18, 45, 3, 1234, tzinfo=met))
2562ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2563ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_tz_aware_arithmetic(self):
2564ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        import random
2565ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2566ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        now = self.theclass.now()
2567ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        tz55 = FixedOffset(-330, "west 5:30")
2568ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        timeaware = now.time().replace(tzinfo=tz55)
2569ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        nowaware = self.theclass.combine(now.date(), timeaware)
2570ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(nowaware.tzinfo is tz55)
2571ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(nowaware.timetz(), timeaware)
2572ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2573ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Can't mix aware and non-aware.
2574ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: now - nowaware)
2575ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: nowaware - now)
2576ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2577ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # And adding datetime's doesn't make sense, aware or not.
2578ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: now + nowaware)
2579ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: nowaware + now)
2580ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: nowaware + nowaware)
2581ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2582ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Subtracting should yield 0.
2583ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(now - now, timedelta(0))
2584ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(nowaware - nowaware, timedelta(0))
2585ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2586ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Adding a delta should preserve tzinfo.
2587ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        delta = timedelta(weeks=1, minutes=12, microseconds=5678)
2588ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        nowawareplus = nowaware + delta
2589ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(nowaware.tzinfo is tz55)
2590ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        nowawareplus2 = delta + nowaware
2591ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(nowawareplus2.tzinfo is tz55)
2592ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(nowawareplus, nowawareplus2)
2593ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2594ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # that - delta should be what we started with, and that - what we
2595ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # started with should be delta.
2596ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        diff = nowawareplus - delta
2597ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(diff.tzinfo is tz55)
2598ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(nowaware, diff)
2599ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: delta - nowawareplus)
2600ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(nowawareplus - nowaware, delta)
2601ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2602ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Make up a random timezone.
2603ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        tzr = FixedOffset(random.randrange(-1439, 1440), "randomtimezone")
2604ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Attach it to nowawareplus.
2605ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        nowawareplus = nowawareplus.replace(tzinfo=tzr)
2606ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(nowawareplus.tzinfo is tzr)
2607ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Make sure the difference takes the timezone adjustments into account.
2608ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        got = nowaware - nowawareplus
2609ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Expected:  (nowaware base - nowaware offset) -
2610ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #            (nowawareplus base - nowawareplus offset) =
2611ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #            (nowaware base - nowawareplus base) +
2612ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #            (nowawareplus offset - nowaware offset) =
2613ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #            -delta + nowawareplus offset - nowaware offset
2614ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        expected = nowawareplus.utcoffset() - nowaware.utcoffset() - delta
2615ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(got, expected)
2616ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2617ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Try max possible difference.
2618ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        min = self.theclass(1, 1, 1, tzinfo=FixedOffset(1439, "min"))
2619ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        max = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999999,
2620ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                            tzinfo=FixedOffset(-1439, "max"))
2621ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        maxdiff = max - min
2622ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(maxdiff, self.theclass.max - self.theclass.min +
2623ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                  timedelta(minutes=2*1439))
2624ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2625ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_tzinfo_now(self):
2626ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        meth = self.theclass.now
2627ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Ensure it doesn't require tzinfo (i.e., that this doesn't blow up).
2628ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base = meth()
2629ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Try with and without naming the keyword.
2630ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        off42 = FixedOffset(42, "42")
2631ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        another = meth(off42)
2632ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        again = meth(tz=off42)
2633ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(another.tzinfo is again.tzinfo)
2634ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(another.utcoffset(), timedelta(minutes=42))
2635ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Bad argument with and w/o naming the keyword.
2636ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, meth, 16)
2637ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, meth, tzinfo=16)
2638ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Bad keyword name.
2639ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, meth, tinfo=off42)
2640ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Too many args.
2641ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, meth, off42, off42)
2642ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2643ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # We don't know which time zone we're in, and don't have a tzinfo
2644ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # class to represent it, so seeing whether a tz argument actually
2645ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # does a conversion is tricky.
2646ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        weirdtz = FixedOffset(timedelta(hours=15, minutes=58), "weirdtz", 0)
2647ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        utc = FixedOffset(0, "utc", 0)
2648ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for dummy in range(3):
2649ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            now = datetime.now(weirdtz)
2650ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertTrue(now.tzinfo is weirdtz)
2651ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            utcnow = datetime.utcnow().replace(tzinfo=utc)
2652ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            now2 = utcnow.astimezone(weirdtz)
2653ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if abs(now - now2) < timedelta(seconds=30):
2654ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                break
2655ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Else the code is broken, or more than 30 seconds passed between
2656ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # calls; assuming the latter, just try again.
2657ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
2658ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Three strikes and we're out.
2659ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.fail("utcnow(), now(tz), or astimezone() may be broken")
2660ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2661ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_tzinfo_fromtimestamp(self):
2662ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        import time
2663ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        meth = self.theclass.fromtimestamp
2664ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ts = time.time()
2665ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Ensure it doesn't require tzinfo (i.e., that this doesn't blow up).
2666ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base = meth(ts)
2667ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Try with and without naming the keyword.
2668ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        off42 = FixedOffset(42, "42")
2669ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        another = meth(ts, off42)
2670ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        again = meth(ts, tz=off42)
2671ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(another.tzinfo is again.tzinfo)
2672ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(another.utcoffset(), timedelta(minutes=42))
2673ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Bad argument with and w/o naming the keyword.
2674ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, meth, ts, 16)
2675ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, meth, ts, tzinfo=16)
2676ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Bad keyword name.
2677ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, meth, ts, tinfo=off42)
2678ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Too many args.
2679ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, meth, ts, off42, off42)
2680ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Too few args.
2681ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, meth)
2682ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2683ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Try to make sure tz= actually does some conversion.
2684ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        timestamp = 1000000000
2685ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        utcdatetime = datetime.utcfromtimestamp(timestamp)
2686ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # In POSIX (epoch 1970), that's 2001-09-09 01:46:40 UTC, give or take.
2687ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # But on some flavor of Mac, it's nowhere near that.  So we can't have
2688ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # any idea here what time that actually is, we can only test that
2689ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # relative changes match.
2690ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        utcoffset = timedelta(hours=-15, minutes=39) # arbitrary, but not zero
2691ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        tz = FixedOffset(utcoffset, "tz", 0)
2692ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        expected = utcdatetime + utcoffset
2693ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        got = datetime.fromtimestamp(timestamp, tz)
2694ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(expected, got.replace(tzinfo=None))
2695ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2696ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_tzinfo_utcnow(self):
2697ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        meth = self.theclass.utcnow
2698ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Ensure it doesn't require tzinfo (i.e., that this doesn't blow up).
2699ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base = meth()
2700ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Try with and without naming the keyword; for whatever reason,
2701ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # utcnow() doesn't accept a tzinfo argument.
2702ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        off42 = FixedOffset(42, "42")
2703ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, meth, off42)
2704ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, meth, tzinfo=off42)
2705ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2706ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_tzinfo_utcfromtimestamp(self):
2707ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        import time
2708ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        meth = self.theclass.utcfromtimestamp
2709ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ts = time.time()
2710ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Ensure it doesn't require tzinfo (i.e., that this doesn't blow up).
2711ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base = meth(ts)
2712ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Try with and without naming the keyword; for whatever reason,
2713ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # utcfromtimestamp() doesn't accept a tzinfo argument.
2714ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        off42 = FixedOffset(42, "42")
2715ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, meth, ts, off42)
2716ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, meth, ts, tzinfo=off42)
2717ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2718ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_tzinfo_timetuple(self):
2719ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # TestDateTime tested most of this.  datetime adds a twist to the
2720ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # DST flag.
2721ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class DST(tzinfo):
2722ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def __init__(self, dstvalue):
2723ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if isinstance(dstvalue, int):
2724ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    dstvalue = timedelta(minutes=dstvalue)
2725ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.dstvalue = dstvalue
2726ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def dst(self, dt):
2727ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return self.dstvalue
2728ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2729ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        cls = self.theclass
2730ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for dstvalue, flag in (-33, 1), (33, 1), (0, 0), (None, -1):
2731ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            d = cls(1, 1, 1, 10, 20, 30, 40, tzinfo=DST(dstvalue))
2732ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            t = d.timetuple()
2733ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(1, t.tm_year)
2734ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(1, t.tm_mon)
2735ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(1, t.tm_mday)
2736ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(10, t.tm_hour)
2737ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(20, t.tm_min)
2738ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(30, t.tm_sec)
2739ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(0, t.tm_wday)
2740ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(1, t.tm_yday)
2741ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(flag, t.tm_isdst)
2742ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2743ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # dst() returns wrong type.
2744ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, cls(1, 1, 1, tzinfo=DST("x")).timetuple)
2745ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2746ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # dst() at the edge.
2747ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(cls(1,1,1, tzinfo=DST(1439)).timetuple().tm_isdst, 1)
2748ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(cls(1,1,1, tzinfo=DST(-1439)).timetuple().tm_isdst, 1)
2749ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2750ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # dst() out of range.
2751ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, cls(1,1,1, tzinfo=DST(1440)).timetuple)
2752ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, cls(1,1,1, tzinfo=DST(-1440)).timetuple)
2753ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2754ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_utctimetuple(self):
2755ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class DST(tzinfo):
2756ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def __init__(self, dstvalue):
2757ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if isinstance(dstvalue, int):
2758ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    dstvalue = timedelta(minutes=dstvalue)
2759ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.dstvalue = dstvalue
2760ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def dst(self, dt):
2761ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return self.dstvalue
2762ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2763ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        cls = self.theclass
2764ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # This can't work:  DST didn't implement utcoffset.
2765ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(NotImplementedError,
2766ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                          cls(1, 1, 1, tzinfo=DST(0)).utcoffset)
2767ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2768ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class UOFS(DST):
2769ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def __init__(self, uofs, dofs=None):
2770ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                DST.__init__(self, dofs)
2771ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.uofs = timedelta(minutes=uofs)
2772ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def utcoffset(self, dt):
2773ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return self.uofs
2774ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2775ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Ensure tm_isdst is 0 regardless of what dst() says:  DST is never
2776ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # in effect for a UTC time.
2777ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for dstvalue in -33, 33, 0, None:
2778ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            d = cls(1, 2, 3, 10, 20, 30, 40, tzinfo=UOFS(-53, dstvalue))
2779ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            t = d.utctimetuple()
2780ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(d.year, t.tm_year)
2781ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(d.month, t.tm_mon)
2782ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(d.day, t.tm_mday)
2783ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(11, t.tm_hour) # 20mm + 53mm = 1hn + 13mm
2784ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(13, t.tm_min)
2785ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(d.second, t.tm_sec)
2786ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(d.weekday(), t.tm_wday)
2787ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(d.toordinal() - date(1, 1, 1).toordinal() + 1,
2788ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             t.tm_yday)
2789ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(0, t.tm_isdst)
2790ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2791ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # At the edges, UTC adjustment can normalize into years out-of-range
2792ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # for a datetime object.  Ensure that a correct timetuple is
2793ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # created anyway.
2794ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        tiny = cls(MINYEAR, 1, 1, 0, 0, 37, tzinfo=UOFS(1439))
2795ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # That goes back 1 minute less than a full day.
2796ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = tiny.utctimetuple()
2797ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.tm_year, MINYEAR-1)
2798ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.tm_mon, 12)
2799ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.tm_mday, 31)
2800ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.tm_hour, 0)
2801ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.tm_min, 1)
2802ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.tm_sec, 37)
2803ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.tm_yday, 366)    # "year 0" is a leap year
2804ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.tm_isdst, 0)
2805ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2806ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        huge = cls(MAXYEAR, 12, 31, 23, 59, 37, 999999, tzinfo=UOFS(-1439))
2807ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # That goes forward 1 minute less than a full day.
2808ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t = huge.utctimetuple()
2809ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.tm_year, MAXYEAR+1)
2810ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.tm_mon, 1)
2811ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.tm_mday, 1)
2812ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.tm_hour, 23)
2813ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.tm_min, 58)
2814ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.tm_sec, 37)
2815ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.tm_yday, 1)
2816ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t.tm_isdst, 0)
2817ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2818ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_tzinfo_isoformat(self):
2819ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        zero = FixedOffset(0, "+00:00")
2820ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        plus = FixedOffset(220, "+03:40")
2821ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        minus = FixedOffset(-231, "-03:51")
2822ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        unknown = FixedOffset(None, "")
2823ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2824ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        cls = self.theclass
2825ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        datestr = '0001-02-03'
2826ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for ofs in None, zero, plus, minus, unknown:
2827ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            for us in 0, 987001:
2828ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                d = cls(1, 2, 3, 4, 5, 59, us, tzinfo=ofs)
2829ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                timestr = '04:05:59' + (us and '.987001' or '')
2830ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                ofsstr = ofs is not None and d.tzname() or ''
2831ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                tailstr = timestr + ofsstr
2832ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                iso = d.isoformat()
2833ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.assertEqual(iso, datestr + 'T' + tailstr)
2834ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.assertEqual(iso, d.isoformat('T'))
2835ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.assertEqual(d.isoformat('k'), datestr + 'k' + tailstr)
2836ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.assertEqual(str(d), datestr + ' ' + tailstr)
2837ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2838ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_replace(self):
2839ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        cls = self.theclass
2840ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        z100 = FixedOffset(100, "+100")
2841ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        zm200 = FixedOffset(timedelta(minutes=-200), "-200")
2842ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        args = [1, 2, 3, 4, 5, 6, 7, z100]
2843ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base = cls(*args)
2844ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(base, base.replace())
2845ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2846ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        i = 0
2847ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for name, newval in (("year", 2),
2848ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             ("month", 3),
2849ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             ("day", 4),
2850ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             ("hour", 5),
2851ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             ("minute", 6),
2852ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             ("second", 7),
2853ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             ("microsecond", 8),
2854ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             ("tzinfo", zm200)):
2855ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            newargs = args[:]
2856ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            newargs[i] = newval
2857ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            expected = cls(*newargs)
2858ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            got = base.replace(**{name: newval})
2859ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(expected, got)
2860ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            i += 1
2861ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2862ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Ensure we can get rid of a tzinfo.
2863ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(base.tzname(), "+100")
2864ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base2 = base.replace(tzinfo=None)
2865ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(base2.tzinfo is None)
2866ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(base2.tzname() is None)
2867ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2868ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Ensure we can add one.
2869ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base3 = base2.replace(tzinfo=z100)
2870ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(base, base3)
2871ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(base.tzinfo is base3.tzinfo)
2872ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2873ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Out of bounds.
2874ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base = cls(2000, 2, 29)
2875ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, base.replace, year=2001)
2876ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2877ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_more_astimezone(self):
2878ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # The inherited test_astimezone covered some trivial and error cases.
2879ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        fnone = FixedOffset(None, "None")
2880ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        f44m = FixedOffset(44, "44")
2881ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        fm5h = FixedOffset(-timedelta(hours=5), "m300")
2882ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2883ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt = self.theclass.now(tz=f44m)
2884ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(dt.tzinfo is f44m)
2885ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Replacing with degenerate tzinfo raises an exception.
2886ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, dt.astimezone, fnone)
2887ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Ditto with None tz.
2888ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, dt.astimezone, None)
2889ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Replacing with same tzinfo makes no change.
2890ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        x = dt.astimezone(dt.tzinfo)
2891ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(x.tzinfo is f44m)
2892ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(x.date(), dt.date())
2893ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(x.time(), dt.time())
2894ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2895ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Replacing with different tzinfo does adjust.
2896ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        got = dt.astimezone(fm5h)
2897ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(got.tzinfo is fm5h)
2898ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(got.utcoffset(), timedelta(hours=-5))
2899ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        expected = dt - dt.utcoffset()  # in effect, convert to UTC
2900ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        expected += fm5h.utcoffset(dt)  # and from there to local time
2901ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        expected = expected.replace(tzinfo=fm5h) # and attach new tzinfo
2902ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(got.date(), expected.date())
2903ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(got.time(), expected.time())
2904ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(got.timetz(), expected.timetz())
2905ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(got.tzinfo is expected.tzinfo)
2906ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(got, expected)
2907ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2908ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_aware_subtract(self):
2909ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        cls = self.theclass
2910ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2911ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Ensure that utcoffset() is ignored when the operands have the
2912ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # same tzinfo member.
2913ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class OperandDependentOffset(tzinfo):
2914ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def utcoffset(self, t):
2915ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if t.minute < 10:
2916ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    # d0 and d1 equal after adjustment
2917ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    return timedelta(minutes=t.minute)
2918ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                else:
2919ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    # d2 off in the weeds
2920ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    return timedelta(minutes=59)
2921ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2922ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base = cls(8, 9, 10, 11, 12, 13, 14, tzinfo=OperandDependentOffset())
2923ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        d0 = base.replace(minute=3)
2924ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        d1 = base.replace(minute=9)
2925ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        d2 = base.replace(minute=11)
2926ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for x in d0, d1, d2:
2927ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            for y in d0, d1, d2:
2928ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                got = x - y
2929ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                expected = timedelta(minutes=x.minute - y.minute)
2930ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.assertEqual(got, expected)
2931ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2932ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # OTOH, if the tzinfo members are distinct, utcoffsets aren't
2933ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # ignored.
2934ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        base = cls(8, 9, 10, 11, 12, 13, 14)
2935ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        d0 = base.replace(minute=3, tzinfo=OperandDependentOffset())
2936ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        d1 = base.replace(minute=9, tzinfo=OperandDependentOffset())
2937ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        d2 = base.replace(minute=11, tzinfo=OperandDependentOffset())
2938ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for x in d0, d1, d2:
2939ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            for y in d0, d1, d2:
2940ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                got = x - y
2941ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if (x is d0 or x is d1) and (y is d0 or y is d1):
2942ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    expected = timedelta(0)
2943ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                elif x is y is d2:
2944ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    expected = timedelta(0)
2945ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                elif x is d2:
2946ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    expected = timedelta(minutes=(11-59)-0)
2947ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                else:
2948ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    assert y is d2
2949ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    expected = timedelta(minutes=0-(11-59))
2950ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.assertEqual(got, expected)
2951ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2952ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_mixed_compare(self):
2953ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 = datetime(1, 2, 3, 4, 5, 6, 7)
2954ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = datetime(1, 2, 3, 4, 5, 6, 7)
2955ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1, t2)
2956ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = t2.replace(tzinfo=None)
2957ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1, t2)
2958ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = t2.replace(tzinfo=FixedOffset(None, ""))
2959ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1, t2)
2960ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = t2.replace(tzinfo=FixedOffset(0, ""))
2961ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: t1 == t2)
2962ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2963ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # In datetime w/ identical tzinfo objects, utcoffset is ignored.
2964ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class Varies(tzinfo):
2965ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def __init__(self):
2966ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.offset = timedelta(minutes=22)
2967ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def utcoffset(self, t):
2968ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.offset += timedelta(minutes=1)
2969ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return self.offset
2970ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2971ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        v = Varies()
2972ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t1 = t2.replace(tzinfo=v)
2973ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = t2.replace(tzinfo=v)
2974ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1.utcoffset(), timedelta(minutes=23))
2975ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t2.utcoffset(), timedelta(minutes=24))
2976ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(t1, t2)
2977ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2978ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # But if they're not identical, it isn't ignored.
2979ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        t2 = t2.replace(tzinfo=Varies())
2980ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(t1 < t2)  # t1's offset counter still going up
2981ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2982ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_subclass_datetimetz(self):
2983ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2984ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class C(self.theclass):
2985ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            theAnswer = 42
2986ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2987ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def __new__(cls, *args, **kws):
2988ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                temp = kws.copy()
2989ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                extra = temp.pop('extra')
2990ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                result = self.theclass.__new__(cls, *args, **temp)
2991ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                result.extra = extra
2992ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return result
2993ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2994ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def newmeth(self, start):
2995ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return start + self.hour + self.year
2996ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2997ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        args = 2002, 12, 31, 4, 5, 6, 500, FixedOffset(-300, "EST", 1)
2998ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
2999ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt1 = self.theclass(*args)
3000ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt2 = C(*args, **{'extra': 7})
3001ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3002ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2.__class__, C)
3003ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2.theAnswer, 42)
3004ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2.extra, 7)
3005ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt1.utcoffset(), dt2.utcoffset())
3006ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt2.newmeth(-7), dt1.hour + dt1.year - 7)
3007ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3008ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# Pain to set up DST-aware tzinfo classes.
3009ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3010ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdef first_sunday_on_or_after(dt):
3011ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    days_to_go = 6 - dt.weekday()
3012ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if days_to_go:
3013ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dt += timedelta(days_to_go)
3014ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    return dt
3015ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3016ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehZERO = timedelta(0)
3017ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehHOUR = timedelta(hours=1)
3018ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehDAY = timedelta(days=1)
3019ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# In the US, DST starts at 2am (standard time) on the first Sunday in April.
3020ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehDSTSTART = datetime(1, 4, 1, 2)
3021ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# and ends at 2am (DST time; 1am standard time) on the last Sunday of Oct,
3022ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# which is the first Sunday on or after Oct 25.  Because we view 1:MM as
3023ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# being standard time on that day, there is no spelling in local time of
3024ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# the last hour of DST (that's 1:MM DST, but 1:MM is taken as standard time).
3025ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehDSTEND = datetime(1, 10, 25, 1)
3026ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3027ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass USTimeZone(tzinfo):
3028ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3029ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def __init__(self, hours, reprname, stdname, dstname):
3030ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.stdoffset = timedelta(hours=hours)
3031ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.reprname = reprname
3032ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.stdname = stdname
3033ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.dstname = dstname
3034ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3035ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def __repr__(self):
3036ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return self.reprname
3037ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3038ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def tzname(self, dt):
3039ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.dst(dt):
3040ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return self.dstname
3041ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
3042ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return self.stdname
3043ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3044ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def utcoffset(self, dt):
3045ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return self.stdoffset + self.dst(dt)
3046ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3047ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def dst(self, dt):
3048ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if dt is None or dt.tzinfo is None:
3049ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # An exception instead may be sensible here, in one or more of
3050ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # the cases.
3051ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return ZERO
3052ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        assert dt.tzinfo is self
3053ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3054ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Find first Sunday in April.
3055ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        start = first_sunday_on_or_after(DSTSTART.replace(year=dt.year))
3056ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        assert start.weekday() == 6 and start.month == 4 and start.day <= 7
3057ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3058ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Find last Sunday in October.
3059ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        end = first_sunday_on_or_after(DSTEND.replace(year=dt.year))
3060ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        assert end.weekday() == 6 and end.month == 10 and end.day >= 25
3061ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3062ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Can't compare naive to aware objects, so strip the timezone from
3063ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # dt first.
3064ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if start <= dt.replace(tzinfo=None) < end:
3065ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return HOUR
3066ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
3067ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return ZERO
3068ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3069ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehEastern  = USTimeZone(-5, "Eastern",  "EST", "EDT")
3070ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehCentral  = USTimeZone(-6, "Central",  "CST", "CDT")
3071ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehMountain = USTimeZone(-7, "Mountain", "MST", "MDT")
3072ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehPacific  = USTimeZone(-8, "Pacific",  "PST", "PDT")
3073ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehutc_real = FixedOffset(0, "UTC", 0)
3074ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# For better test coverage, we want another flavor of UTC that's west of
3075ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# the Eastern and Pacific timezones.
3076ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehutc_fake = FixedOffset(-12*60, "UTCfake", 0)
3077ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3078ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass TestTimezoneConversions(unittest.TestCase):
3079ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # The DST switch times for 2002, in std time.
3080ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    dston = datetime(2002, 4, 7, 2)
3081ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    dstoff = datetime(2002, 10, 27, 1)
3082ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3083ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    theclass = datetime
3084ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3085ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Check a time that's inside DST.
3086ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def checkinside(self, dt, tz, utc, dston, dstoff):
3087ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.dst(), HOUR)
3088ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3089ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Conversion to our own timezone is always an identity.
3090ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.astimezone(tz), dt)
3091ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3092ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        asutc = dt.astimezone(utc)
3093ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        there_and_back = asutc.astimezone(tz)
3094ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3095ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Conversion to UTC and back isn't always an identity here,
3096ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # because there are redundant spellings (in local time) of
3097ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # UTC time when DST begins:  the clock jumps from 1:59:59
3098ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # to 3:00:00, and a local time of 2:MM:SS doesn't really
3099ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # make sense then.  The classes above treat 2:MM:SS as
3100ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # daylight time then (it's "after 2am"), really an alias
3101ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # for 1:MM:SS standard time.  The latter form is what
3102ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # conversion back from UTC produces.
3103ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if dt.date() == dston.date() and dt.hour == 2:
3104ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # We're in the redundant hour, and coming back from
3105ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # UTC gives the 1:MM:SS standard-time spelling.
3106ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(there_and_back + HOUR, dt)
3107ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Although during was considered to be in daylight
3108ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # time, there_and_back is not.
3109ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(there_and_back.dst(), ZERO)
3110ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # They're the same times in UTC.
3111ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(there_and_back.astimezone(utc),
3112ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                             dt.astimezone(utc))
3113ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
3114ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # We're not in the redundant hour.
3115ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(dt, there_and_back)
3116ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3117ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Because we have a redundant spelling when DST begins, there is
3118ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # (unfortunately) an hour when DST ends that can't be spelled at all in
3119ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # local time.  When DST ends, the clock jumps from 1:59 back to 1:00
3120ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # again.  The hour 1:MM DST has no spelling then:  1:MM is taken to be
3121ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # standard time.  1:MM DST == 0:MM EST, but 0:MM is taken to be
3122ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # daylight time.  The hour 1:MM daylight == 0:MM standard can't be
3123ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # expressed in local time.  Nevertheless, we want conversion back
3124ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # from UTC to mimic the local clock's "repeat an hour" behavior.
3125ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        nexthour_utc = asutc + HOUR
3126ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        nexthour_tz = nexthour_utc.astimezone(tz)
3127ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if dt.date() == dstoff.date() and dt.hour == 0:
3128ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # We're in the hour before the last DST hour.  The last DST hour
3129ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # is ineffable.  We want the conversion back to repeat 1:MM.
3130ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(nexthour_tz, dt.replace(hour=1))
3131ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            nexthour_utc += HOUR
3132ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            nexthour_tz = nexthour_utc.astimezone(tz)
3133ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(nexthour_tz, dt.replace(hour=1))
3134ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
3135ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(nexthour_tz - dt, HOUR)
3136ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3137ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Check a time that's outside DST.
3138ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def checkoutside(self, dt, tz, utc):
3139ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.dst(), ZERO)
3140ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3141ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Conversion to our own timezone is always an identity.
3142ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt.astimezone(tz), dt)
3143ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3144ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Converting to UTC and back is an identity too.
3145ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        asutc = dt.astimezone(utc)
3146ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        there_and_back = asutc.astimezone(tz)
3147ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(dt, there_and_back)
3148ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3149ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def convert_between_tz_and_utc(self, tz, utc):
3150ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dston = self.dston.replace(tzinfo=tz)
3151ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Because 1:MM on the day DST ends is taken as being standard time,
3152ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # there is no spelling in tz for the last hour of daylight time.
3153ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # For purposes of the test, the last hour of DST is 0:MM, which is
3154ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # taken as being daylight time (and 1:MM is taken as being standard
3155ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # time).
3156ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dstoff = self.dstoff.replace(tzinfo=tz)
3157ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for delta in (timedelta(weeks=13),
3158ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                      DAY,
3159ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                      HOUR,
3160ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                      timedelta(minutes=1),
3161ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                      timedelta(microseconds=1)):
3162ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3163ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.checkinside(dston, tz, utc, dston, dstoff)
3164ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            for during in dston + delta, dstoff - delta:
3165ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.checkinside(during, tz, utc, dston, dstoff)
3166ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3167ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.checkoutside(dstoff, tz, utc)
3168ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            for outside in dston - delta, dstoff + delta:
3169ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.checkoutside(outside, tz, utc)
3170ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3171ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_easy(self):
3172ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Despite the name of this test, the endcases are excruciating.
3173ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.convert_between_tz_and_utc(Eastern, utc_real)
3174ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.convert_between_tz_and_utc(Pacific, utc_real)
3175ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.convert_between_tz_and_utc(Eastern, utc_fake)
3176ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.convert_between_tz_and_utc(Pacific, utc_fake)
3177ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # The next is really dancing near the edge.  It works because
3178ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Pacific and Eastern are far enough apart that their "problem
3179ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # hours" don't overlap.
3180ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.convert_between_tz_and_utc(Eastern, Pacific)
3181ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.convert_between_tz_and_utc(Pacific, Eastern)
3182ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # OTOH, these fail!  Don't enable them.  The difficulty is that
3183ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # the edge case tests assume that every hour is representable in
3184ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # the "utc" class.  This is always true for a fixed-offset tzinfo
3185ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # class (lke utc_real and utc_fake), but not for Eastern or Central.
3186ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # For these adjacent DST-aware time zones, the range of time offsets
3187ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # tested ends up creating hours in the one that aren't representable
3188ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # in the other.  For the same reason, we would see failures in the
3189ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Eastern vs Pacific tests too if we added 3*HOUR to the list of
3190ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # offset deltas in convert_between_tz_and_utc().
3191ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #
3192ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # self.convert_between_tz_and_utc(Eastern, Central)  # can't work
3193ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # self.convert_between_tz_and_utc(Central, Eastern)  # can't work
3194ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3195ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_tricky(self):
3196ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # 22:00 on day before daylight starts.
3197ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        fourback = self.dston - timedelta(hours=4)
3198ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ninewest = FixedOffset(-9*60, "-0900", 0)
3199ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        fourback = fourback.replace(tzinfo=ninewest)
3200ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # 22:00-0900 is 7:00 UTC == 2:00 EST == 3:00 DST.  Since it's "after
3201ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # 2", we should get the 3 spelling.
3202ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # If we plug 22:00 the day before into Eastern, it "looks like std
3203ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # time", so its offset is returned as -5, and -5 - -9 = 4.  Adding 4
3204ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # to 22:00 lands on 2:00, which makes no sense in local time (the
3205ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # local clock jumps from 1 to 3).  The point here is to make sure we
3206ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # get the 3 spelling.
3207ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        expected = self.dston.replace(hour=3)
3208ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        got = fourback.astimezone(Eastern).replace(tzinfo=None)
3209ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(expected, got)
3210ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3211ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Similar, but map to 6:00 UTC == 1:00 EST == 2:00 DST.  In that
3212ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # case we want the 1:00 spelling.
3213ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        sixutc = self.dston.replace(hour=6, tzinfo=utc_real)
3214ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Now 6:00 "looks like daylight", so the offset wrt Eastern is -4,
3215ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # and adding -4-0 == -4 gives the 2:00 spelling.  We want the 1:00 EST
3216ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # spelling.
3217ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        expected = self.dston.replace(hour=1)
3218ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        got = sixutc.astimezone(Eastern).replace(tzinfo=None)
3219ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(expected, got)
3220ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3221ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Now on the day DST ends, we want "repeat an hour" behavior.
3222ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #  UTC  4:MM  5:MM  6:MM  7:MM  checking these
3223ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #  EST 23:MM  0:MM  1:MM  2:MM
3224ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #  EDT  0:MM  1:MM  2:MM  3:MM
3225ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # wall  0:MM  1:MM  1:MM  2:MM  against these
3226ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for utc in utc_real, utc_fake:
3227ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            for tz in Eastern, Pacific:
3228ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                first_std_hour = self.dstoff - timedelta(hours=2) # 23:MM
3229ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # Convert that to UTC.
3230ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                first_std_hour -= tz.utcoffset(None)
3231ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # Adjust for possibly fake UTC.
3232ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                asutc = first_std_hour + utc.utcoffset(None)
3233ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # First UTC hour to convert; this is 4:00 when utc=utc_real &
3234ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # tz=Eastern.
3235ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                asutcbase = asutc.replace(tzinfo=utc)
3236ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                for tzhour in (0, 1, 1, 2):
3237ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    expectedbase = self.dstoff.replace(hour=tzhour)
3238ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    for minute in 0, 30, 59:
3239ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        expected = expectedbase.replace(minute=minute)
3240ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        asutc = asutcbase.replace(minute=minute)
3241ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        astz = asutc.astimezone(tz)
3242ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        self.assertEqual(astz.replace(tzinfo=None), expected)
3243ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    asutcbase += HOUR
3244ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3245ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3246ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_bogus_dst(self):
3247ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class ok(tzinfo):
3248ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def utcoffset(self, dt): return HOUR
3249ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def dst(self, dt): return HOUR
3250ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3251ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        now = self.theclass.now().replace(tzinfo=utc_real)
3252ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Doesn't blow up.
3253ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        now.astimezone(ok())
3254ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3255ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Does blow up.
3256ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class notok(ok):
3257ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def dst(self, dt): return None
3258ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, now.astimezone, notok())
3259ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3260ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_fromutc(self):
3261ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, Eastern.fromutc)   # not enough args
3262ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        now = datetime.utcnow().replace(tzinfo=utc_real)
3263ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(ValueError, Eastern.fromutc, now) # wrong tzinfo
3264ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        now = now.replace(tzinfo=Eastern)   # insert correct tzinfo
3265ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        enow = Eastern.fromutc(now)         # doesn't blow up
3266ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(enow.tzinfo, Eastern) # has right tzinfo member
3267ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, Eastern.fromutc, now, now) # too many args
3268ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, Eastern.fromutc, date.today()) # wrong type
3269ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3270ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Always converts UTC to standard time.
3271ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        class FauxUSTimeZone(USTimeZone):
3272ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            def fromutc(self, dt):
3273ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return dt + self.stdoffset
3274ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        FEastern  = FauxUSTimeZone(-5, "FEastern",  "FEST", "FEDT")
3275ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3276ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #  UTC  4:MM  5:MM  6:MM  7:MM  8:MM  9:MM
3277ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #  EST 23:MM  0:MM  1:MM  2:MM  3:MM  4:MM
3278ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        #  EDT  0:MM  1:MM  2:MM  3:MM  4:MM  5:MM
3279ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3280ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Check around DST start.
3281ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        start = self.dston.replace(hour=4, tzinfo=Eastern)
3282ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        fstart = start.replace(tzinfo=FEastern)
3283ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for wall in 23, 0, 1, 3, 4, 5:
3284ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            expected = start.replace(hour=wall)
3285ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if wall == 23:
3286ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                expected -= timedelta(days=1)
3287ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            got = Eastern.fromutc(start)
3288ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(expected, got)
3289ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3290ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            expected = fstart + FEastern.stdoffset
3291ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            got = FEastern.fromutc(fstart)
3292ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(expected, got)
3293ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3294ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Ensure astimezone() calls fromutc() too.
3295ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            got = fstart.replace(tzinfo=utc_real).astimezone(FEastern)
3296ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(expected, got)
3297ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3298ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            start += HOUR
3299ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            fstart += HOUR
3300ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3301ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Check around DST end.
3302ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        start = self.dstoff.replace(hour=4, tzinfo=Eastern)
3303ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        fstart = start.replace(tzinfo=FEastern)
3304ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for wall in 0, 1, 1, 2, 3, 4:
3305ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            expected = start.replace(hour=wall)
3306ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            got = Eastern.fromutc(start)
3307ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(expected, got)
3308ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3309ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            expected = fstart + FEastern.stdoffset
3310ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            got = FEastern.fromutc(fstart)
3311ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(expected, got)
3312ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3313ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Ensure astimezone() calls fromutc() too.
3314ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            got = fstart.replace(tzinfo=utc_real).astimezone(FEastern)
3315ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.assertEqual(expected, got)
3316ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3317ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            start += HOUR
3318ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            fstart += HOUR
3319ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3320ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3321ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh#############################################################################
3322ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# oddballs
3323ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3324ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass Oddballs(unittest.TestCase):
3325ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3326ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def test_bug_1028306(self):
3327ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Trying to compare a date to a datetime should act like a mixed-
3328ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # type comparison, despite that datetime is a subclass of date.
3329ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        as_date = date.today()
3330ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        as_datetime = datetime.combine(as_date, time())
3331ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(as_date != as_datetime)
3332ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(as_datetime != as_date)
3333ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(not as_date == as_datetime)
3334ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(not as_datetime == as_date)
3335ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: as_date < as_datetime)
3336ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: as_datetime < as_date)
3337ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: as_date <= as_datetime)
3338ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: as_datetime <= as_date)
3339ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: as_date > as_datetime)
3340ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: as_datetime > as_date)
3341ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: as_date >= as_datetime)
3342ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertRaises(TypeError, lambda: as_datetime >= as_date)
3343ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3344ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Neverthelss, comparison should work with the base-class (date)
3345ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # projection if use of a date method is forced.
3346ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(as_date.__eq__(as_datetime))
3347ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        different_day = (as_date.day + 1) % 20 + 1
3348ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertTrue(not as_date.__eq__(as_datetime.replace(day=
3349ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                                     different_day)))
3350ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3351ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # And date should compare with other subclasses of date.  If a
3352ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # subclass wants to stop this, it's up to the subclass to do so.
3353ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        date_sc = SubclassDate(as_date.year, as_date.month, as_date.day)
3354ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(as_date, date_sc)
3355ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(date_sc, as_date)
3356ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3357ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Ditto for datetimes.
3358ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        datetime_sc = SubclassDatetime(as_datetime.year, as_datetime.month,
3359ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                       as_date.day, 0, 0, 0)
3360ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(as_datetime, datetime_sc)
3361ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.assertEqual(datetime_sc, as_datetime)
3362ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3363ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdef test_main():
3364ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    test_support.run_unittest(__name__)
3365ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3366ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehif __name__ == "__main__":
3367ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    test_main()
3368