Django timezone.make_aware在2014-10-26 1:45:00引发了AmbiguousTimeError

时间:2014-10-20 11:54:12

标签: python django timezone pytz

我发现了一些奇怪的事情。这里有一些例子。

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

然后好玩的开始

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     

在2014-10-26 00:59:00和2014-10-26 02:00:00

之间提出了AmbiguousTimeError

为什么?怎么解决呢?

2 个答案:

答案 0 :(得分:3)

timezon.make_aware(d, TZ)相当于TZ.localize(d, is_dst=None)因模糊时间而引发错误:2014-10-26 01:45:00在欧洲/莫斯科时区发生两次:

# 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

注意:凌晨2点(Федеральный закон от 21 июля 2014 г. N 248-ФЗ),utc偏移从+0400更改为+0300

为了避免异常,你可以调用TZ.localize(d)(注意:没有is_dst=None),对于现有的非模糊时间可以正常工作,但对于不存在或不明确的时间可能会失败(返回错误的答案)

如果pytz Bug #1378150: Enhance support for end-of-DST-like ambiguous time已修复,那么您可以使用TZ.localize(d, is_dst=True)TZ.localize(d, is_dst=False)来相应地转换前后的时间。

如果错误未得到解决,您可以使用Parsing of Ordered Timestamps in Local Time (to UTC) While Observing Daylight Saving Time的答案在过渡后获得的时间:

# `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)

答案 1 :(得分:1)

这是因为夏令时。

10月26日凌晨2点,莫斯科人将时钟缩短一小时。这意味着他们将在那天看到两次,例如,凌晨1:30。因此,凌晨1点到凌晨2点之间的时间不明确,Python / pytz告诉你。

如何处理这将是特定于应用程序的。您需要决定您正在谈论的是哪一个上午1:30(即您正在谈论的UTC时间)。

(显然这是大多数俄罗斯人去年处理夏令时的最后一年。请参阅this article了解一些有趣的背景。)