2
# -*- coding: ascii -*-
4
$Id: test_tzinfo.py,v 1.9 2004/10/25 04:14:00 zenzen Exp $
7
__rcs_id__ = '$Id: test_tzinfo.py,v 1.9 2004/10/25 04:14:00 zenzen Exp $'
8
__version__ = '$Revision: 1.9 $'[11:-2]
11
sys.path.insert(0, os.pardir)
13
import unittest, doctest
14
from datetime import datetime, tzinfo, timedelta
15
import pytz, reference
17
fmt = '%Y-%m-%d %H:%M:%S %Z%z'
21
UTC = pytz.timezone('UTC')
22
REF_UTC = reference.UTC
24
class BasicTest(unittest.TestCase):
26
now = datetime.now(tz=UTC)
27
self.failUnless(now.utcoffset() == NOTIME)
28
self.failUnless(now.dst() == NOTIME)
29
self.failUnless(now.timetuple() == now.utctimetuple())
31
def testReferenceUTC(self):
32
now = datetime.now(tz=REF_UTC)
33
self.failUnless(now.utcoffset() == NOTIME)
34
self.failUnless(now.dst() == NOTIME)
35
self.failUnless(now.timetuple() == now.utctimetuple())
38
class USEasternDSTStartTestCase(unittest.TestCase):
39
tzinfo = pytz.timezone('US/Eastern')
41
# 24 hours before DST changeover
42
transition_time = datetime(2002, 4, 7, 7, 0, 0, tzinfo=UTC)
44
# Increase for 'flexible' DST transitions due to 1 minute granularity
45
# of Python's datetime library
46
instant = timedelta(seconds=1)
51
'utcoffset': timedelta(hours = -5),
52
'dst': timedelta(hours = 0),
58
'utcoffset': timedelta(hours = -4),
59
'dst': timedelta(hours = 1),
62
def _test_tzname(self, utc_dt, wanted):
63
dt = utc_dt.astimezone(self.tzinfo)
64
self.failUnlessEqual(dt.tzname(),wanted['tzname'],
65
'Expected %s as tzname for %s. Got %s' % (
66
wanted['tzname'],str(utc_dt),dt.tzname()
70
def _test_utcoffset(self, utc_dt, wanted):
71
utcoffset = wanted['utcoffset']
72
dt = utc_dt.astimezone(self.tzinfo)
74
dt.utcoffset(),utcoffset,
75
'Expected %s as utcoffset for %s. Got %s' % (
76
utcoffset,utc_dt,dt.utcoffset()
80
dt_wanted = utc_dt.replace(tzinfo=None) + utcoffset
81
dt_got = dt.replace(tzinfo=None)
85
'Got %s. Wanted %s' % (str(dt_got),str(dt_wanted))
88
def _test_dst(self, utc_dt, wanted):
90
dt = utc_dt.astimezone(self.tzinfo)
91
self.failUnlessEqual(dt.dst(),dst,
92
'Expected %s as dst for %s. Got %s' % (
97
def test_arithmetic(self):
98
utc_dt = self.transition_time
100
for days in range(-420, 720, 20):
101
delta = timedelta(days=days)
103
# Make sure we can get back where we started
104
dt = utc_dt.astimezone(self.tzinfo)
107
self.failUnlessEqual(dt, dt2)
109
# Make sure arithmetic crossing DST boundaries ends
110
# up in the correct timezone after normalization
111
self.failUnlessEqual(
112
(utc_dt + delta).astimezone(self.tzinfo).strftime(fmt),
113
self.tzinfo.normalize(dt + delta).strftime(fmt),
114
'Incorrect result for delta==%d days. Wanted %r. Got %r'%(
116
(utc_dt + delta).astimezone(self.tzinfo).strftime(fmt),
117
self.tzinfo.normalize(dt + delta).strftime(fmt),
121
def _test_all(self, utc_dt, wanted):
122
self._test_utcoffset(utc_dt, wanted)
123
self._test_tzname(utc_dt, wanted)
124
self._test_dst(utc_dt, wanted)
126
def testDayBefore(self):
128
self.transition_time - timedelta(days=1), self.before
131
def testTwoHoursBefore(self):
133
self.transition_time - timedelta(hours=2), self.before
136
def testHourBefore(self):
138
self.transition_time - timedelta(hours=1), self.before
141
def testInstantBefore(self):
143
self.transition_time - self.instant, self.before
146
def testTransition(self):
148
self.transition_time, self.after
151
def testInstantAfter(self):
153
self.transition_time + self.instant, self.after
156
def testHourAfter(self):
158
self.transition_time + timedelta(hours=1), self.after
161
def testTwoHoursAfter(self):
163
self.transition_time + timedelta(hours=1), self.after
166
def testDayAfter(self):
168
self.transition_time + timedelta(days=1), self.after
172
class USEasternDSTEndTestCase(USEasternDSTStartTestCase):
173
tzinfo = pytz.timezone('US/Eastern')
174
transition_time = datetime(2002, 10, 27, 6, 0, 0, tzinfo=UTC)
177
'utcoffset': timedelta(hours = -4),
178
'dst': timedelta(hours = 1),
182
'utcoffset': timedelta(hours = -5),
183
'dst': timedelta(hours = 0),
187
class USEasternEPTStartTestCase(USEasternDSTStartTestCase):
188
transition_time = datetime(1945, 8, 14, 23, 0, 0, tzinfo=UTC)
191
'utcoffset': timedelta(hours = -4),
192
'dst': timedelta(hours = 1),
196
'utcoffset': timedelta(hours = -4),
197
'dst': timedelta(hours = 1),
201
class USEasternEPTEndTestCase(USEasternDSTStartTestCase):
202
transition_time = datetime(1945, 9, 30, 6, 0, 0, tzinfo=UTC)
205
'utcoffset': timedelta(hours = -4),
206
'dst': timedelta(hours = 1),
210
'utcoffset': timedelta(hours = -5),
211
'dst': timedelta(hours = 0),
215
class WarsawWMTEndTestCase(USEasternDSTStartTestCase):
216
# In 1915, Warsaw changed from Warsaw to Central European time.
217
# This involved the clocks being set backwards, causing a end-of-DST
218
# like situation without DST being involved.
219
tzinfo = pytz.timezone('Europe/Warsaw')
220
transition_time = datetime(1915, 8, 4, 22, 36, 0, tzinfo=UTC)
223
'utcoffset': timedelta(hours=1, minutes=24),
228
'utcoffset': timedelta(hours=1),
233
class VilniusWMTEndTestCase(USEasternDSTStartTestCase):
234
# At the end of 1916, Vilnius changed timezones putting its clock
235
# forward by 11 minutes 35 seconds. Neither timezone was in DST mode.
236
tzinfo = pytz.timezone('Europe/Vilnius')
237
instant = timedelta(seconds=31)
238
transition_time = datetime(1916, 12, 31, 22, 36, 00, tzinfo=UTC)
241
'utcoffset': timedelta(hours=1, minutes=24),
246
'utcoffset': timedelta(hours=1, minutes=36), # Really 1:35:36
251
class ReferenceUSEasternDSTStartTestCase(USEasternDSTStartTestCase):
252
tzinfo = reference.Eastern
253
def test_arithmetic(self):
254
# Reference implementation cannot handle this
258
class ReferenceUSEasternDSTEndTestCase(USEasternDSTEndTestCase):
259
tzinfo = reference.Eastern
261
def testHourBefore(self):
262
# Python's datetime library has a bug, where the hour before
263
# a daylight savings transition is one hour out. For example,
264
# at the end of US/Eastern daylight savings time, 01:00 EST
265
# occurs twice (once at 05:00 UTC and once at 06:00 UTC),
266
# whereas the first should actually be 01:00 EDT.
267
# Note that this bug is by design - by accepting this ambiguity
268
# for one hour one hour per year, an is_dst flag on datetime.time
269
# became unnecessary.
271
self.transition_time - timedelta(hours=1), self.after
274
def testInstantBefore(self):
276
self.transition_time - timedelta(seconds=1), self.after
279
def test_arithmetic(self):
280
# Reference implementation cannot handle this
284
class LocalTestCase(unittest.TestCase):
285
def testLocalize(self):
286
loc_tz = pytz.timezone('Europe/Amsterdam')
288
loc_time = loc_tz.localize(datetime(1930, 5, 10, 0, 0, 0))
289
# Actually +00:19:32, but Python datetime rounds this
290
self.failUnlessEqual(loc_time.strftime('%Z%z'), 'AMT+0020')
292
loc_time = loc_tz.localize(datetime(1930, 5, 20, 0, 0, 0))
293
# Actually +00:19:32, but Python datetime rounds this
294
self.failUnlessEqual(loc_time.strftime('%Z%z'), 'NST+0120')
296
loc_time = loc_tz.localize(datetime(1940, 5, 10, 0, 0, 0))
297
self.failUnlessEqual(loc_time.strftime('%Z%z'), 'NET+0020')
299
loc_time = loc_tz.localize(datetime(1940, 5, 20, 0, 0, 0))
300
self.failUnlessEqual(loc_time.strftime('%Z%z'), 'CEST+0200')
302
loc_time = loc_tz.localize(datetime(2004, 2, 1, 0, 0, 0))
303
self.failUnlessEqual(loc_time.strftime('%Z%z'), 'CET+0100')
305
loc_time = loc_tz.localize(datetime(2004, 4, 1, 0, 0, 0))
306
self.failUnlessEqual(loc_time.strftime('%Z%z'), 'CEST+0200')
308
tz = pytz.timezone('Europe/Amsterdam')
309
loc_time = loc_tz.localize(datetime(1943, 3, 29, 1, 59, 59))
310
self.failUnlessEqual(loc_time.strftime('%Z%z'), 'CET+0100')
314
loc_tz = pytz.timezone('US/Eastern')
316
# End of DST ambiguity check
317
loc_time = loc_tz.localize(datetime(1918, 10, 27, 1, 59, 59), is_dst=1)
318
self.failUnlessEqual(loc_time.strftime('%Z%z'), 'EDT-0400')
320
loc_time = loc_tz.localize(datetime(1918, 10, 27, 1, 59, 59), is_dst=0)
321
self.failUnlessEqual(loc_time.strftime('%Z%z'), 'EST-0500')
323
self.failUnlessRaises(pytz.AmbiguousTimeError,
324
loc_tz.localize, datetime(1918, 10, 27, 1, 59, 59), is_dst=None
327
# Weird changes - war time and peace time both is_dst==True
329
loc_time = loc_tz.localize(datetime(1942, 2, 9, 3, 0, 0))
330
self.failUnlessEqual(loc_time.strftime('%Z%z'), 'EWT-0400')
332
loc_time = loc_tz.localize(datetime(1945, 8, 14, 19, 0, 0))
333
self.failUnlessEqual(loc_time.strftime('%Z%z'), 'EPT-0400')
335
loc_time = loc_tz.localize(datetime(1945, 9, 30, 1, 0, 0), is_dst=1)
336
self.failUnlessEqual(loc_time.strftime('%Z%z'), 'EPT-0400')
338
loc_time = loc_tz.localize(datetime(1945, 9, 30, 1, 0, 0), is_dst=0)
339
self.failUnlessEqual(loc_time.strftime('%Z%z'), 'EST-0500')
341
def testNormalize(self):
342
tz = pytz.timezone('US/Eastern')
343
dt = datetime(2004, 4, 4, 7, 0, 0, tzinfo=UTC).astimezone(tz)
344
dt2 = dt - timedelta(minutes=10)
345
self.failUnlessEqual(
346
dt2.strftime('%Y-%m-%d %H:%M:%S %Z%z'),
347
'2004-04-04 02:50:00 EDT-0400'
350
dt2 = tz.normalize(dt2)
351
self.failUnlessEqual(
352
dt2.strftime('%Y-%m-%d %H:%M:%S %Z%z'),
353
'2004-04-04 01:50:00 EST-0500'
356
def testPartialMinuteOffsets(self):
357
# utcoffset in Amsterdam was not a whole minute until 1937
358
# However, we fudge this by rounding them, as the Python
360
tz = pytz.timezone('Europe/Amsterdam')
361
utc_dt = datetime(1914, 1, 1, 13, 40, 28, tzinfo=UTC) # correct
362
utc_dt = utc_dt.replace(second=0) # But we need to fudge it
363
loc_dt = utc_dt.astimezone(tz)
364
self.failUnlessEqual(
365
loc_dt.strftime('%Y-%m-%d %H:%M:%S %Z%z'),
366
'1914-01-01 14:00:00 AMT+0020'
370
utc_dt = loc_dt.astimezone(UTC)
371
self.failUnlessEqual(
372
utc_dt.strftime('%Y-%m-%d %H:%M:%S %Z%z'),
373
'1914-01-01 13:40:00 UTC+0000'
376
def no_testCreateLocaltime(self):
377
# It would be nice if this worked, but it doesn't.
378
tz = pytz.timezone('Europe/Amsterdam')
379
dt = datetime(2004, 10, 31, 2, 0, 0, tzinfo=tz)
380
self.failUnlessEqual(
382
'2004-10-31 02:00:00 CET+0100'
386
suite = unittest.TestSuite()
387
suite.addTest(doctest.DocTestSuite('pytz'))
388
suite.addTest(doctest.DocTestSuite('pytz.tzinfo'))
389
suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(
390
__import__('__main__')
394
if __name__ == '__main__':
397
runner = unittest.TextTestRunner(verbosity=2)
399
runner = unittest.TextTestRunner()
402
# vim: set filetype=python ts=4 sw=4 et