Python datetime对象显示错误的时区偏移量

com*_*ugs 28 python datetime pytz

我尝试使用datetime和pytz在python中创建一个datetime对象,显示的偏移是错误的.

import datetime
from pytz import timezone

start = datetime.datetime(2011, 6, 20, 0, 0, 0, 0, timezone('Asia/Kolkata'))
print start
Run Code Online (Sandbox Code Playgroud)

显示的输出是

datetime.datetime(2011, 6, 20, 0, 0, tzinfo=<DstTzInfo 'Asia/Kolkata' HMT+5:53:00 STD>)
Run Code Online (Sandbox Code Playgroud)

请注意,'Asia/Kolkata'是IST,GMT + 5:30,而不是HMT + 5:53.这是一个标准的linux时区,为什么我会弄错,我该如何解决呢?

Fer*_*yer 50

请参阅:http://bytes.com/topic/python/answers/676275-pytz-giving-incorrect-offset-timezone

在评论中,有人建议使用tzinfo.localize()而不是datetime构造函数,这可以解决问题.

>>> tz = timezone('Asia/Kolkata')
>>> dt = tz.localize(datetime.datetime(2011, 6, 20, 0, 0, 0, 0))
>>> dt
datetime.datetime(2011, 6, 20, 0, 0, tzinfo=<DstTzInfo 'Asia/Kolkata' IST+5:30:00 STD>)
Run Code Online (Sandbox Code Playgroud)

更新:实际上,官方的pytz网站声明你应该总是使用localizeastimezone代替传递时区对象datetime.datetime.

  • 这太疯狂了.感谢您的回答. (8认同)
  • 这个答案可以通过添加一个小推理来改进,为什么“pytz”默认使用带有分钟偏移量的极其不常见的时区,并且在使用方法“.localize()”时不使用它们。这太奇怪了。 (2认同)

Rec*_*nic 9

这个问题已在 python >=3.9 中由标准库中的zoneinfo模块修复。>= 3.9 中的解决方案可能是停止使用 pytz。

In [1]: import datetime

In [2]: from zoneinfo import ZoneInfo

In [3]: start = datetime.datetime(2011, 6, 20, 0, 0, 0, 0, ZoneInfo('Asia/Kolkata'))

In [4]: print(start)
2011-06-20 00:00:00+05:30
Run Code Online (Sandbox Code Playgroud)

这种极其令人困惑的行为的原因是,时区过去没有以 :30 或 :00 偏移量进行标准化。在 20 世纪初,大多数都采用了标准胶印。在 OP 的示例中,时区切换于 1906 年。对于美国/中部地区,这发生在 1901 年。

from datetime import datetime, timedelta, date
from pytz import timezone

d = datetime.combine(date.today(), time.min)
for tz in ('Asia/Kolkata', "US/Central"):
    while d > datetime(1800, 1, 1):
        localized = timezone(tz).localize(d)
        if localized.isoformat()[-2:] not in ("00", "30"):
            print(tz)
            print(localized.isoformat())
            print(timezone(tz).localize(d + timedelta(days=1)).isoformat())
            break
        d -= timedelta(days=1)
Run Code Online (Sandbox Code Playgroud)

输出:

Asia/Kolkata
1906-01-01T00:00:00+05:21
1906-01-02T00:00:00+05:30
US/Central
1901-12-13T00:00:00-05:51
1901-12-14T00:00:00-06:00
Run Code Online (Sandbox Code Playgroud)

当 Pytz 没有日期信息时,它似乎只使用最旧的偏移量,即使它是很久以前的事。在一些非常自然的构造中,例如将 tzinfo 传递给日期时间构造函数,时区对象不会获得该数据。