I found some strange things. Here some examples.
from django.utils import timezone
value = u'2014-10-26 01:45:00'
#I know that a variable has 'Europe / Moscow' timezone. Let's tell Django about it.
TZ = timezone.pytz.timezone('Europe/Moscow')
d = timezone.datetime.strptime(value,'%Y-%m-%d %H:%M:%S')
print timezone.make_aware(d,TZ)
#raised AmbiguousTimeError: 2014-10-26 01:45:00
And then the fun begins
print timezone.make_aware(d+timezone.timedelta(minutes=15),TZ)
#out: 2014-10-26 02:00:00+03:00
print timezone.make_aware(d+timezone.timedelta(minutes=14),TZ)
#raised AmbiguousTimeError
print timezone.make_aware(d-timezone.timedelta(minutes=46),TZ)
#out: 2014-10-26 00:59:00+04:00
print timezone.make_aware(d-timezone.timedelta(minutes=45),TZ)
#raised AmbiguousTimeError
So AmbiguousTimeError raised between 2014-10-26 00:59:00 and 2014-10-26 02:00:00
WHY? And how solve it?
timezon.make_aware(d, TZ)
is equivalent to TZ.localize(d, is_dst=None)
that raises an error for ambiguous times: 2014-10-26 01:45:00
happens twice in Europe/Moscow timezone:
# Europe/Moscow UTC timestamp
2014-10-26 00:45:00 MSK+0400; 2014-10-25 20:45:00 UTC+0000; 1414269900
2014-10-26 01:00:00 MSK+0400; 2014-10-25 21:00:00 UTC+0000; 1414270800
2014-10-26 01:15:00 MSK+0400; 2014-10-25 21:15:00 UTC+0000; 1414271700
2014-10-26 01:30:00 MSK+0400; 2014-10-25 21:30:00 UTC+0000; 1414272600
2014-10-26 01:45:00 MSK+0400; 2014-10-25 21:45:00 UTC+0000; 1414273500
2014-10-26 01:15:00 MSK+0300; 2014-10-25 22:15:00 UTC+0000; 1414275300
2014-10-26 01:30:00 MSK+0300; 2014-10-25 22:30:00 UTC+0000; 1414276200
2014-10-26 01:45:00 MSK+0300; 2014-10-25 22:45:00 UTC+0000; 1414277100
2014-10-26 02:00:00 MSK+0300; 2014-10-25 23:00:00 UTC+0000; 1414278000
Notice: the utc offset is changed from +0400
to +0300
at 2am (Федеральный закон от 21 июля 2014 г. N 248-ФЗ).
To avoid the exception, you could call TZ.localize(d)
(note: no is_dst=None
) that works fine for existing non-ambiguous times but may fail (return wrong answer) for non-existing or ambiguous times.
If pytz Bug #1378150: Enhance support for end-of-DST-like ambiguous time is fixed then you could use TZ.localize(d, is_dst=True)
, TZ.localize(d, is_dst=False)
to get time before and after the transition correspondingly.
If the bug is not fixed you could use my answer from Parsing of Ordered Timestamps in Local Time (to UTC) While Observing Daylight Saving Time to get the time after the transition:
# `naive` is a naive datetime object in local (Europe/Moscow) time
if tz.localize(naive, is_dst=False) == tz.localize(naive, is_dst=True):
# Example: 2014/10/26 in Europe/Moscow timezone
# ambiguous time but is_dst=False/True yield the same result
# i.e., tz.localize() can't help, find UTC time manually
#NOTE: assume there is no other changes to UTC offset today (local.day)
new_offset = tz.localize(naive + timedelta(1), is_dst=None).utcoffset()
assert tz.localize(naive).utcoffset() != new_offset
utc = (naive - new_offset).replace(tzinfo=pytz.utc)
local = utc.astimezone(tz)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With