为什么datetime.datetime.utcnow()不包含时区信息?
datetime.datetime.utcnow()
为什么这个datetime
没有任何时区信息,尽管它明确是一个UTC的datetime
呢?
我本来以为这里应该包含tzinfo
。
10 个回答
在Python的标准库中,直到3.2版本之前都没有包含任何tzinfo类。我只能猜测原因。我个人认为不包含一个用于UTC的tzinfo类是个错误,因为这个类是比较简单明了的,应该有一个标准的实现。虽然库里没有这个实现,但在tzinfo
的文档中有一个示例。
from datetime import timedelta, tzinfo
ZERO = timedelta(0)
# A UTC class.
class UTC(tzinfo):
"""UTC"""
def utcoffset(self, dt):
return ZERO
def tzname(self, dt):
return "UTC"
def dst(self, dt):
return ZERO
utc = UTC()
一旦你有了一个UTC的tzinfo
对象,你仍然不能直接用它来获取当前时间。要得到一个带时区信息的当前时间对象,你需要这样做:
from datetime import datetime
now = datetime.now(utc)
在Python 3.2中,他们终于在库里加入了一个UTC的tzinfo
类:
from datetime import datetime, timezone
now = datetime.now(timezone.utc)
到了Python 3.9,他们为其他所有时区也创建了tzinfo
类。想了解更多细节,可以查看PEP 615 -- 在标准库中支持IANA时区数据库。
注意,从Python 3.2开始,datetime
模块里有了datetime.timezone
。在datetime.utcnow()
的文档中提到:
你可以通过调用
datetime.now
(
timezone.utc
)
来获取一个带有时区信息的当前UTC时间。
所以,datetime.utcnow()
并不会设置tzinfo
来表明它是UTC时间,但datetime.now(datetime.timezone.utc)
会返回带有tzinfo
的UTC时间。
因此,你可以这样做:
>>> import datetime
>>> datetime.datetime.now(datetime.timezone.utc)
datetime.datetime(2014, 7, 10, 2, 43, 55, 230107, tzinfo=datetime.timezone.utc)
自从Python 3.11起,还有一个datetime.UTC
,它和datetime.timezone.utc
是一样的。所以你也可以使用datetime.datetime.now(datetime.UTC)
。
这意味着它没有考虑时区,所以你不能用它来配合 datetime.astimezone
。
你可以像这样给它指定一个时区:
import pytz # 3rd party: $ pip install pytz
u = datetime.utcnow()
u = u.replace(tzinfo=pytz.utc) #NOTE: it works only with a fixed utc offset
现在你可以更改时区了。
print(u.astimezone(pytz.timezone("America/New_York")))
要获取某个时区的当前时间,你可以直接把 tzinfo 传给 datetime.now()
:
#!/usr/bin/env python
from datetime import datetime
import pytz # $ pip install pytz
print(datetime.now(pytz.timezone("America/New_York")))
这适用于任何时区,包括那些会调整夏令时的时区,也就是说,它可以处理在不同时间可能有不同 UTC 偏移量的时区(非固定的 UTC 偏移量)。不要使用 tz.localize(datetime.now())
,因为在夏令时结束时,当本地时间变得模糊时,它可能会出错。