关于python:pytz localize vs datetime replace

pytz localize vs datetime replace

我在pytz的.localize()函数中遇到了一些奇怪的问题。 有时它不会调整本地化的日期时间:

.localize行为:

1
2
3
4
5
6
7
8
9
10
11
>>> tz
<DstTzInfo 'Africa/Abidjan' LMT-1 day, 23:44:00 STD>
>>> d
datetime.datetime(2009, 9, 2, 14, 45, 42, 91421)

>>> tz.localize(d)
datetime.datetime(2009, 9, 2, 14, 45, 42, 91421,
                  tzinfo=<DstTzInfo 'Africa/Abidjan' GMT0:00:00 STD>)
>>> tz.normalize(tz.localize(d))
datetime.datetime(2009, 9, 2, 14, 45, 42, 91421,
                  tzinfo=<DstTzInfo 'Africa/Abidjan' GMT0:00:00 STD>)

如您所见,由于本地化/规范化操作,时间没有改变。
但是,如果使用.replace:

1
2
3
4
5
6
>>> d.replace(tzinfo=tz)
datetime.datetime(2009, 9, 2, 14, 45, 42, 91421,
                  tzinfo=<DstTzInfo 'Africa/Abidjan' LMT-1 day, 23:44:00 STD>)
>>> tz.normalize(d.replace(tzinfo=tz))
datetime.datetime(2009, 9, 2, 15, 1, 42, 91421,
                  tzinfo=<DstTzInfo 'Africa/Abidjan' GMT0:00:00 STD>)

这似乎调整了日期时间。

问题是 - 这是正确的,为什么其他的错?


localize只是假设您传递的天真日期时间是"正确"(除了不知道时区!)因此只设置时区,没有其他调整。

您可以(并且建议......)在内部使用UTC(而不是使用天真的日期时间)并在需要以本地化方式执行日期时间的I / O时使用replace(normalize将处理DST等)。


localize是用于创建具有初始固定日期时间值的日期时间感知对象的正确函数。生成的日期时间感知对象将具有原始日期时间值。在我看来,一个非常常见的使用模式,也许pytz可以更好地记录。

遗憾的是,replace(tzinfo = ...)被命名。它是一个随机行为的函数。我会建议避免使用此功能来设置时区,除非你喜欢自己造成的痛苦。我已经厌倦了使用这个功能。


我意识到我有点迟到了......
但这是我发现运作良好的东西。
亚历克斯说:

1
2
tz = pytz.timezone('Africa/Abidjan')
now = datetime.datetime.utcnow()

然后本地化:

1
2
tzoffset = tz.utcoffset(now)
mynow = now+tzoffset

而且这种方法可以完美地处理DST


此DstTzInfo类用于时区,其中UTC的偏移在某些时间点发生变化。例如(您可能已经知道),许多地点在夏季开始时转换为"夏令时",然后在夏季结束时转回"标准时间"。每个DstTzInfo实例仅代表其中一个时区,但"localize"和"normalize"方法可帮助您获得正确的实例。

对于阿比让来说,只有一次过渡(根据pytz),那是在1912年:

1
2
3
>>> tz = pytz.timezone('Africa/Abidjan')
>>> tz._utc_transition_times
[datetime.datetime(1, 1, 1, 0, 0), datetime.datetime(1912, 1, 1, 0, 16, 8)]

我们从pytz中得到的tz对象代表了1912年以前的时区:

1
2
>>> tz
<DstTzInfo 'Africa/Abidjan' LMT-1 day, 23:44:00 STD>

现在查看你的两个例子,看到当你调用tz.localize(d)时,你不会将这个1912年之前的时区添加到你的天真日期时间对象中。它假定您给出的日期时间对象表示当地时间的正确时区的本地时间,即1912年后的时区。

但是在您使用d.replace(tzinfo = tz)的第二个示例中,它使用您的datetime对象来表示1912年以前时区的时间。这可能不是你的意思。然后当你调用dt.normalize时,它会将其转换为该日期时间值正确的时区,即1912年后的时区。