summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStuart Bishop <stuart@stuartbishop.net>2014-11-03 08:24:30 +0000
committerStuart Bishop <stuart@stuartbishop.net>2014-11-03 08:24:30 +0000
commit25d85435699db22861bdbdcc9d7244f9ea6c220f (patch)
treed5860011c54c4e6f6ea9e24c5bf390fae57af3a1
parent86eb5b8775bd9fa105ddc3338a99c8df6c73c161 (diff)
downloadpytz-25d85435699db22861bdbdcc9d7244f9ea6c220f.tar.gz
Handle non-DST->non-DST transitions better, from jfs per https://bugs.launchpad.net/pytz/+bug/1378150
-rw-r--r--src/pytz/tests/test_tzinfo.py20
-rw-r--r--src/pytz/tzinfo.py17
2 files changed, 27 insertions, 10 deletions
diff --git a/src/pytz/tests/test_tzinfo.py b/src/pytz/tests/test_tzinfo.py
index adf622a..677649d 100644
--- a/src/pytz/tests/test_tzinfo.py
+++ b/src/pytz/tests/test_tzinfo.py
@@ -659,6 +659,23 @@ class LocalTestCase(unittest.TestCase):
loc_time = loc_tz.localize(datetime(1945, 9, 30, 1, 0, 0), is_dst=0)
self.assertEqual(loc_time.strftime('%Z%z'), 'EST-0500')
+ # Weird changes - ambiguous time (end-of-DST like) but is_dst==False
+ for zonename, ambiguous_naive, expected in [
+ ('Europe/Warsaw', datetime(1915, 8, 4, 23, 59, 59),
+ ['1915-08-04 23:59:59 WMT+0124',
+ '1915-08-04 23:59:59 CET+0100']),
+ ('Europe/Moscow', datetime(2014, 10, 26, 1, 30),
+ ['2014-10-26 01:30:00 MSK+0400',
+ '2014-10-26 01:30:00 MSK+0300'])]:
+ loc_tz = pytz.timezone(zonename)
+ self.assertRaises(pytz.AmbiguousTimeError,
+ loc_tz.localize, ambiguous_naive, is_dst=None
+ )
+ # Also test non-boolean is_dst in the weird case
+ for dst in [True, timedelta(1), False, timedelta(0)]:
+ loc_time = loc_tz.localize(ambiguous_naive, is_dst=dst)
+ self.assertEqual(loc_time.strftime(fmt), expected[not dst])
+
def testNormalize(self):
tz = pytz.timezone('US/Eastern')
dt = datetime(2004, 4, 4, 7, 0, 0, tzinfo=UTC).astimezone(tz)
@@ -677,7 +694,7 @@ class LocalTestCase(unittest.TestCase):
def testPartialMinuteOffsets(self):
# utcoffset in Amsterdam was not a whole minute until 1937
# However, we fudge this by rounding them, as the Python
- # datetime library
+ # datetime library
tz = pytz.timezone('Europe/Amsterdam')
utc_dt = datetime(1914, 1, 1, 13, 40, 28, tzinfo=UTC) # correct
utc_dt = utc_dt.replace(second=0) # But we need to fudge it
@@ -817,4 +834,3 @@ def test_suite():
if __name__ == '__main__':
warnings.simplefilter("error") # Warnings should be fatal in tests.
unittest.main(defaultTest='test_suite')
-
diff --git a/src/pytz/tzinfo.py b/src/pytz/tzinfo.py
index d53e9ff..1318872 100644
--- a/src/pytz/tzinfo.py
+++ b/src/pytz/tzinfo.py
@@ -142,7 +142,7 @@ class StaticTzInfo(BaseTzInfo):
def __reduce__(self):
# Special pickle to zone remains a singleton and to cope with
- # database changes.
+ # database changes.
return pytz._p, (self.zone,)
@@ -369,13 +369,15 @@ class DstTzInfo(BaseTzInfo):
# hints to be passed in (such as the UTC offset or abbreviation),
# but that is just getting silly.
#
- # Choose the earliest (by UTC) applicable timezone.
- sorting_keys = {}
+ # Choose the earliest (by UTC) applicable timezone if is_dst=True
+ # Choose the latest (by UTC) applicable timezone if is_dst=False
+ # i.e., behave like end-of-DST transition
+ dates = {} # utc -> local
for local_dt in filtered_possible_loc_dt:
- key = local_dt.replace(tzinfo=None) - local_dt.tzinfo._utcoffset
- sorting_keys[key] = local_dt
- first_key = sorted(sorting_keys)[0]
- return sorting_keys[first_key]
+ utc_time = local_dt.replace(tzinfo=None) - local_dt.tzinfo._utcoffset
+ assert utc_time not in dates
+ dates[utc_time] = local_dt
+ return dates[[min, max][not is_dst](dates)]
def utcoffset(self, dt, is_dst=None):
'''See datetime.tzinfo.utcoffset
@@ -560,4 +562,3 @@ def unpickler(zone, utcoffset=None, dstoffset=None, tzname=None):
inf = (utcoffset, dstoffset, tzname)
tz._tzinfos[inf] = tz.__class__(inf, tz._tzinfos)
return tz._tzinfos[inf]
-