1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
#!/usr/bin/python2.7
import os.path, sys
sys.path.insert(0, os.path.join('build', 'dist'))
from datetime import datetime, timedelta
import re
from time import strptime
import unittest
import pytz
class ZdumpTestCase(unittest.TestCase):
def utc_to_local_check(self, zone, utc_dt, loc_dt, loc_tzname, is_dst):
loc_tz = pytz.timezone(zone)
self.failUnlessEqual(
utc_dt.astimezone(loc_tz).replace(tzinfo=None),
loc_dt.replace(tzinfo=None))
def local_to_utc_check(self, zone, utc_dt, loc_dt, loc_tzname, is_dst):
self.failUnlessEqual(
loc_dt.astimezone(pytz.utc).replace(tzinfo=None),
utc_dt.replace(tzinfo=None))
def test_suite():
testcases = []
raw_data = open(
os.path.join(os.path.dirname(__file__), 'zdump.out'), 'r').readlines()
last_zone = None
test_class = None
zdump_line_re = re.compile(r'''(?x)
^([^\s]+) \s+ (.+) \s UT \s+ = \s+ (.+) \s ([^\s]+) \s+
isdst=(0|1) \s+ gmtoff=[\-\d]+ \s*$
''')
for i in range(0, len(raw_data)):
line = raw_data[i]
m = zdump_line_re.search(line)
if m is None:
raise RuntimeError('Dud line %r' % (line,))
zone, utc_string, loc_string, tzname, is_dst = m.groups()
is_dst = bool(int(is_dst))
if zone != last_zone:
classname = zone.replace(
'+', '_plus_').replace('-', '_minus_').replace('/','_')
test_class = type(classname, (ZdumpTestCase,), {})
testcases.append(test_class)
last_zone = zone
skip_next_local = False
utc_dt = datetime(
*strptime(utc_string, '%a %b %d %H:%M:%S %Y')[:6])
loc_dt = datetime(
*strptime(loc_string, '%a %b %d %H:%M:%S %Y')[:6])
def round_dt(loc_dt, utc_dt):
# Urgh - utcoffset() and dst() have to be rounded to the nearest
# minute, so we need to break our tests to match this limitation
real_offset = loc_dt - utc_dt
secs = real_offset.seconds + real_offset.days*86400
fake_offset = timedelta(seconds=int((secs+30)//60)*60)
return utc_dt + fake_offset
loc_dt = round_dt(loc_dt, utc_dt)
# If the naive time on the next line is less than on this
# line, and we aren't seeing an end-of-dst transition, then
# we can't do our local->utc tests for either this nor the
# next line since we are in an ambiguous time period (ie.
# we have wound back the clock but don't have differing
# is_dst flags to resolve the ambiguity)
skip_local = skip_next_local
skip_next_local = False
try:
m = zdump_line_re.match(raw_data[i+1])
except IndexError:
m = None
if m is not None:
(next_zone, next_utc_string, next_loc_string,
next_tzname, next_is_dst) = m.groups()
next_is_dst = bool(int(next_is_dst))
if next_zone == zone and next_is_dst == is_dst:
next_utc_dt = datetime(
*strptime(next_utc_string, '%a %b %d %H:%M:%S %Y')[:6])
next_loc_dt = round_dt(
datetime(*strptime(
next_loc_string, '%a %b %d %H:%M:%S %Y')[:6]),
next_utc_dt)
if next_loc_dt <= loc_dt:
skip_local = True
skip_next_local = True
loc_tz = pytz.timezone(zone)
loc_dt = loc_tz.localize(loc_dt, is_dst)
utc_dt = pytz.utc.localize(utc_dt)
test_name = 'test_utc_to_local_%04d_%02d_%02d_%02d_%02d_%02d' % (
utc_dt.year, utc_dt.month, utc_dt.day,
utc_dt.hour, utc_dt.minute, utc_dt.second)
def test_utc_to_local(
self, zone=zone, utc_dt=utc_dt, loc_dt=loc_dt, tzname=tzname,
is_dst=is_dst):
self.utc_to_local_check(zone, utc_dt, loc_dt, tzname, is_dst)
test_utc_to_local.__name__ = test_name
setattr(test_class, test_name, test_utc_to_local)
if not skip_local:
test_name = 'test_local_to_utc_%04d_%02d_%02d_%02d_%02d_%02d' % (
loc_dt.year, loc_dt.month, loc_dt.day,
loc_dt.hour, loc_dt.minute, loc_dt.second)
if is_dst:
test_name += '_dst'
else:
test_name += '_nodst'
def test_local_to_utc(
self, zone=zone, utc_dt=utc_dt, loc_dt=loc_dt, tzname=tzname,
is_dst=is_dst):
self.local_to_utc_check(zone, utc_dt, loc_dt, tzname, is_dst)
test_local_to_utc.__name__ = test_name
setattr(test_class, test_name, test_local_to_utc)
classname = zone.replace(
'+', '_plus_').replace('-', '_minus_').replace('/','_')
test_class = type(classname, (ZdumpTestCase,), {})
testcases.append(test_class)
suite = unittest.TestSuite()
while testcases:
suite.addTest(unittest.makeSuite(testcases.pop()))
return suite
if __name__ == '__main__':
unittest.main(defaultTest='test_suite')
|