diff options
author | Stuart Bishop <stuart@stuartbishop.net> | 2009-09-29 02:49:44 +0700 |
---|---|---|
committer | Stuart Bishop <stuart@stuartbishop.net> | 2009-09-29 02:49:44 +0700 |
commit | 112de0583c188e16b82e935ab8802615b3f05e08 (patch) | |
tree | 4d69f87288ea7cb9889028fe9462ba71e5d86c08 | |
parent | 6b8aa43f84b50c1cfb72e47d5ca857fd9df340ff (diff) | |
download | pytz-112de0583c188e16b82e935ab8802615b3f05e08.tar.gz |
Fix skip_local in zdump, handle dst transition with no actual wallclock time change
-rw-r--r-- | gen_tzinfo.py | 4 | ||||
-rw-r--r-- | src/pytz/tzfile.py | 3 | ||||
-rw-r--r-- | src/pytz/tzinfo.py | 12 | ||||
-rw-r--r-- | test_zdump.py | 75 |
4 files changed, 59 insertions, 35 deletions
diff --git a/gen_tzinfo.py b/gen_tzinfo.py index ddeb7e5..5db2792 100644 --- a/gen_tzinfo.py +++ b/gen_tzinfo.py @@ -27,7 +27,7 @@ def allzones(): ]) stripnum = len(os.path.commonprefix(zones)) zones = [z[stripnum:] for z in zones] - + if target: wanted = target + ['US/Eastern', 'UTC'] zones = [z for z in zones if z in wanted] @@ -128,7 +128,7 @@ def add_allzones(filename): def main(destdir): _destdir = os.path.join(os.path.abspath(destdir), 'dist') - + dupe_src(_destdir) add_allzones(os.path.join(_destdir, 'pytz', '__init__.py')) diff --git a/src/pytz/tzfile.py b/src/pytz/tzfile.py index ea8032a..88f4320 100644 --- a/src/pytz/tzfile.py +++ b/src/pytz/tzfile.py @@ -91,6 +91,9 @@ def build_tzinfo(zone, fp): break # Found std time. dst = inf[0] - stdinf[0] + if dst == 0: # Can't calculate the dst offset, so use 1hr. + dst = 3600 + tzname = inf[2] # Round utcoffset and dst to the nearest minute or the diff --git a/src/pytz/tzinfo.py b/src/pytz/tzinfo.py index ed035a3..f31dc90 100644 --- a/src/pytz/tzinfo.py +++ b/src/pytz/tzinfo.py @@ -250,12 +250,14 @@ class DstTzInfo(BaseTzInfo): if dt.tzinfo is not None: raise ValueError, 'Not naive datetime (tzinfo is already set)' - # Find the possibly correct timezones. We probably just have one, - # but we might end up with two if we are in the end-of-DST - # transition period. Or possibly more in some particularly confused - # location... + # Find the two best possibilities. possible_loc_dt = set() - for tzinfo in self._tzinfos.values(): + for delta in [timedelta(days=-1), timedelta(days=1)]: + loc_dt = dt + delta + idx = max(0, bisect_right( + self._utc_transition_times, loc_dt) - 1) + inf = self._transition_info[idx] + tzinfo = self._tzinfos[inf] loc_dt = tzinfo.normalize(dt.replace(tzinfo=tzinfo)) if loc_dt.replace(tzinfo=None) == dt: possible_loc_dt.add(loc_dt) diff --git a/test_zdump.py b/test_zdump.py index 9e5b440..c815a28 100644 --- a/test_zdump.py +++ b/test_zdump.py @@ -28,20 +28,17 @@ def test_suite(): testcases = [] raw_data = open( os.path.join(os.path.dirname(__file__), 'zdump.out'), 'r').readlines() - raw_data.reverse() # Keep tests running in alphabetical order last_zone = None test_class = None - for line in raw_data: - m = re.match( - r'^([^\s]+) \s+ (.+) \s UTC \s+ = \s+ (.+) \s ([^\s]+) \s+ ' - r'isdst=(0|1)$', - line, re.X - ) - if m: - zone, utc_string, loc_string, tzname, is_dst = m.groups() - else: + zdump_line_re = re.compile(r'''(?x) + ^([^\s]+) \s+ (.+) \s UTC \s+ = \s+ (.+) \s ([^\s]+) \s+ isdst=(0|1)$ + ''') + 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: @@ -50,31 +47,49 @@ def test_suite(): test_class = type(classname, (ZdumpTestCase,), {}) testcases.append(test_class) last_zone = zone - prev_loc_dt = None - prev_is_dst = False + 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]) - # 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) - loc_dt = utc_dt + fake_offset + 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 previous line is greater than on this + # If the naive time on the next line is less than on this # line, and we arn't seeing an end-of-dst transition, then - # we can't do our local->utc test 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 = ( - prev_loc_dt is not None and prev_loc_dt > loc_dt and - bool(prev_is_dst) == bool(is_dst)) - prev_loc_dt = loc_dt - prev_is_dst = is_dst + # 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) @@ -106,6 +121,10 @@ def test_suite(): 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: |