62

我对 pytz 的 .localize() 函数有一些奇怪的问题。有时它不会对本地化的日期时间进行调整:

.localize 行为:

>>> 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:

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

这似乎对日期时间进行了调整。

问题是-哪个是正确的,为什么其他人是错的?

4

4 回答 4

51

localize只是假设你传递的天真日期时间是“正确的”(除了不知道时区!),所以只是设置时区,没有其他调整。

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

于 2009-09-04T15:12:52.100 回答
25

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

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

于 2017-03-30T20:30:24.760 回答
11

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

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

>>> 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 年以前的时区:

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

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

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

于 2009-10-20T06:40:10.903 回答
8

我意识到我在这方面有点晚了……但这是我发现效果很好的方法。正如 Alex 所说,在 UTC 工作:

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

然后进行本地化:

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

而且这种方法确实可以完美地处理夏令时

于 2011-01-14T17:23:16.093 回答