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

datetime.datetime.utcnow()

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

我希望这将包含 tzinfo

259232 次浏览

UTC日期不需要任何时区信息,因为它们是UTC,这根据定义意味着它们没有偏移量。

标准的Python库直到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对象,你仍然不能将它与utcnow一起使用。获取当前时间作为感知datetime对象:

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

这意味着它是无时区的,所以不能与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")))

它适用于任何时区,包括那些遵守日光节约时间(DST)的时区,即,它适用于可能在不同时间具有不同utc偏移量的时区(非固定utc偏移量)。不要使用tz.localize(datetime.now())——当本地时间不明确时,它可能会在dst结束转换期间失败。

pytz模块是一个选项,还有另一个python-dateutil,虽然也是第三方包,但可能已经可用,这取决于你的其他依赖项和操作系统。

我只是想包括这个方法作为参考——如果你已经为其他目的安装了python-dateutil,你可以使用它的tzinfo,而不是用pytz复制

import datetime
import dateutil.tz


# Get the UTC time with datetime.now:
utcdt = datetime.datetime.now(dateutil.tz.tzutc())


# Get the UTC time with datetime.utcnow:
utcdt = datetime.datetime.utcnow()
utcdt = utcdt.replace(tzinfo=dateutil.tz.tzutc())


# For fun- get the local time
localdt = datetime.datetime.now(dateutil.tz.tzlocal())

我倾向于同意调用utcnow应该包含UTC时区信息。我怀疑这没有包括在内,因为本机datetime库默认为naive datetimes以实现交叉兼容性。

注意,对于Python 3.2以后,datetime模块包含datetime.timezonedatetime.utcnow()的文档说:

可感知的当前UTC日期时间可以通过调用datetime.now(timezone.utc)来获得。

因此,datetime.utcnow()不会设置tzinfo来表示它是UTC,但datetime.now(datetime.timezone.utc)确实返回UTC时间 tzinfo set。

所以你可以这样做:

>>> import datetime
>>> datetime.datetime.now(datetime.timezone.utc)
datetime.datetime(2014, 7, 10, 2, 43, 55, 230107, tzinfo=datetime.timezone.utc)
from datetime import datetime
from dateutil.relativedelta import relativedelta
d = datetime.now()
date = datetime.isoformat(d).split('.')[0]
d_month = datetime.today() + relativedelta(months=1)
next_month = datetime.isoformat(d_month).split('.')[0]

Julien Danjou写了一篇很好的文章来解释为什么永远不要处理时区问题。摘录:

实际上,Python datetime API总是返回未意识到的datetime对象, 这是非常不幸的。的确,只要你有了这个 对象,没有办法知道时区是什么,因此这些 对象本身就很“没用”。

唉,即使你可以使用utcnow(),你仍然不会看到时区信息,正如你所发现的。

建议:

  • 始终使用感知的datetime对象,即带有时区信息。那 确保你可以直接比较它们(aware和unconscious datetime . 对象是不可比较的),并将它们正确地返回给用户。 利用pytz来拥有时区对象。李< / p > < / >

  • 使用ISO 8601作为输入和 输出字符串格式。使用datetime.datetime.isoformat()返回 时间戳作为使用该格式格式化的字符串,其中包括 李时区信息。< / p > < / > 如果你需要解析包含ISO 8601格式时间戳的字符串, 你可以依赖iso8601,它返回带有correct的时间戳 时区信息。

在Python 3.2+中添加timezone信息

import datetime


>>> d = datetime.datetime.now(tz=datetime.timezone.utc)
>>> print(d.tzinfo)
'UTC+00:00'

datetime.datetime.utcnow()返回UTC时间为朴素datetime对象的行为显然有问题,必须修复。如果您的系统本地时区不是UTC,可能会导致意想不到的结果,因为datetime库假定天真的datetime对象来表示系统本地时间。例如,datetime.datetime.utcnow().timestaamp()给出的时间戳比我计算机上的正确值提前4小时。此外,从python 3.6开始,datetime.astimezone()可以在天真的datetime实例上调用,但datetime.datetime.utcnow().astimezone(any_timezone)会给出错误的结果,除非你的系统本地时区是UTC。

它还应该包括和now()问题有关。

因此,在此之前,now()优先于today()utcnow()

from datetime import datetime, timezone
utc = timezone.utc
date = datetime.now(utc)
print(date) # 2022-04-06 05:40:13.025347+00:00