为什么datetime.datetime.utcnow()不包含时区信息?

467 投票
10 回答
326692 浏览
提问于 2025-04-15 19:42
datetime.datetime.utcnow()

为什么这个datetime没有任何时区信息,尽管它明确是一个UTC的datetime呢?

我本来以为这里应该包含tzinfo

10 个回答

88

在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时区数据库

358

注意,从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)

250

这意味着它没有考虑时区,所以你不能用它来配合 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()),因为在夏令时结束时,当本地时间变得模糊时,它可能会出错。

撰写回答