如何在Python中获得“时区感知”的datetime.today()值?

506 投票
19 回答
636323 浏览
提问于 2025-04-16 09:01

我想从当前的日期时间中减去一个日期值,以计算某件事情发生了多久。但是它给我报错:

TypeError: can't subtract offset-naive and offset-aware datetimes

datetime.datetime.today() 返回的值似乎没有“时区信息”,而我其他的日期值是有时区的。我该怎么做才能让 datetime.datetime.today() 返回一个带有时区信息的值呢?

理想的情况是它能自动识别时区。

现在,它给我的时间是本地时间,恰好是太平洋标准时间(PST),也就是UTC - 8小时。最糟糕的情况是,我能否手动把一个时区值输入到 datetime 对象中,并把它设置为UTC-8呢?

19 个回答

184

在 Python 3.9 及以上版本中:使用 zoneinfo 来处理 IANA 时区数据库:

在 Python 3.9 或更高版本中,你可以通过标准库来指定特定的时区,使用 zoneinfo,像这样:

>>> import datetime
>>> from zoneinfo import ZoneInfo
>>> datetime.datetime.now(ZoneInfo("America/Los_Angeles"))
datetime.datetime(2020, 11, 27, 6, 34, 34, 74823, tzinfo=zoneinfo.ZoneInfo(key='America/Los_Angeles'))

zoneinfo 的时区数据库来自操作系统。如果你的操作系统没有 IANA 的时区数据库(比如 Windows),那么它会从一个叫 tzdata 的第三方包中获取这些信息,如果这个包可用的话。

在 Python 3.2 或更高版本中:

如果你需要指定 UTC 作为时区,标准库在 Python 3.2 或更高版本中提供了支持:

>>> datetime.datetime.now(datetime.timezone.utc)
datetime.datetime(2020, 11, 27, 14, 34, 34, 74823, tzinfo=datetime.timezone.utc)

你还可以使用 astimezone 来获取包含本地时间偏移的日期时间:

>>> datetime.datetime.now(datetime.timezone.utc).astimezone()
datetime.datetime(2020, 11, 27, 15, 34, 34, 74823, tzinfo=datetime.timezone(datetime.timedelta(seconds=3600), 'CET'))

在 Python 3.6 或更高版本中,你可以把最后一行简化为:

>>> datetime.datetime.now().astimezone()
datetime.datetime(2020, 11, 27, 15, 34, 34, 74823, tzinfo=datetime.timezone(datetime.timedelta(seconds=3600), 'CET'))

如果你想要一个只使用标准库,并且在 Python 2 和 Python 3 中都能工作的解决方案,可以查看 jfs 的回答

197

获取当前时间,按照特定的时区:

import datetime
import pytz
my_date = datetime.datetime.now(pytz.timezone('US/Pacific'))

记得先安装 pytz 这个库。

505

在标准库中,没有跨平台的方法可以创建带时区的时间,除非你自己写一个时区类。补充:Python 3.9 引入了 zoneinfo,这个功能现在可以在标准库中找到。

在Windows上,有 win32timezone.utcnow(),但这属于pywin32库。我更推荐使用 pytz库,它有一个不断更新的大部分时区的数据库。

处理本地时区可能会非常棘手(可以查看下面的“进一步阅读”链接),所以你可能更想在整个应用程序中使用UTC,特别是在进行像计算两个时间点之间的差异这样的算术操作时。

你可以这样获取当前的日期和时间:

import pytz
from datetime import datetime
datetime.utcnow().replace(tzinfo=pytz.utc)

要注意的是,datetime.today()datetime.now() 返回的是 本地 时间,而不是UTC时间,所以对它们使用 .replace(tzinfo=pytz.utc) 是不正确的。

还有一种更简洁的方法:

datetime.now(pytz.utc)

这个方法稍微短一些,但效果是一样的。


进一步阅读/观看为什么在很多情况下更喜欢使用UTC:

撰写回答