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

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

datetime.datetime.utcnow()

datetime鉴于它明确是UTC,为什么没有任何时区信息datetime

我希望这将包含tzinfo

datetime.datetime.utcnow()

Why does this datetime not have any timezone info given that it is explicitly a UTC datetime?

I would expect that this would contain tzinfo.


回答 0

这意味着它是时区幼稚的,所以您不能将其与 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结束过渡期间可能会失败。

That means it is timezone naive, so you can’t use it with datetime.astimezone

you can give it a timezone like this

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

now you can change timezones

print(u.astimezone(pytz.timezone("America/New_York")))

To get the current time in a given timezone, you could pass tzinfo to datetime.now() directly:

#!/usr/bin/env python
from datetime import datetime
import pytz # $ pip install pytz

print(datetime.now(pytz.timezone("America/New_York")))

It works for any timezone including those that observe daylight saving time (DST) i.e., it works for timezones that may have different utc offsets at different times (non-fixed utc offset). Don’t use tz.localize(datetime.now()) — it may fail during end-of-DST transition when the local time is ambiguous.


回答 1

请注意,对于Python 3.2及更高版本,该datetime模块包含datetime.timezone。文档datetime.utcnow()说明:

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

因此,您可以执行以下操作:

>>> import datetime
>>> datetime.datetime.now(datetime.timezone.utc)
datetime.datetime(2014, 7, 10, 2, 43, 55, 230107, tzinfo=datetime.timezone.utc)

Note that for Python 3.2 onwards, the datetime module contains datetime.timezone. The documentation for datetime.utcnow() says:

An aware current UTC datetime can be obtained by calling datetime.now(timezone.utc).

So, datetime.utcnow() doesn’t set tzinfo to indicate that it is UTC, but datetime.now(datetime.timezone.utc) does return UTC time with tzinfo set.

So you can do:

>>> import datetime
>>> datetime.datetime.now(datetime.timezone.utc)
datetime.datetime(2014, 7, 10, 2, 43, 55, 230107, tzinfo=datetime.timezone.utc)

回答 2

标准的Python库不包含任何tzinfo类(但请参见pep 431)。我只能猜测原因。我个人认为不为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()

要使用它,以将当前时间作为已知的datetime对象获取:

from datetime import datetime 

now = datetime.now(utc)

datetime.timezone.utc在Python 3.2+:

from datetime import datetime, timezone 

now = datetime.now(timezone.utc)

The standard Python libraries don’t include any tzinfo classes (but see pep 431). I can only guess at the reasons. Personally I think it was a mistake not to include a tzinfo class for UTC, because that one is uncontroversial enough to have a standard implementation.

Edit: Although there’s no implementation in the library, there is one given as an example in the tzinfo documentation.

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()

To use it, to get the current time as an aware datetime object:

from datetime import datetime 

now = datetime.now(utc)

There is datetime.timezone.utc in Python 3.2+:

from datetime import datetime, timezone 

now = datetime.now(timezone.utc)

回答 3

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时区信息。我怀疑这不包括在内,因为本机日期时间库默认为天真日期时间以实现交叉兼容性。

The pytz module is one option, and there is another python-dateutil, which although is also third party package, may already be available depending on your other dependencies and operating system.

I just wanted to include this methodology for reference- if you’ve already installed python-dateutil for other purposes, you can use its tzinfo instead of duplicating with 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())

I tend to agree that calls to utcnow should include the UTC timezone information. I suspect that this is not included because the native datetime library defaults to naive datetimes for cross compatibility.


回答 4

朱利安•丹乔(Julien Danjou)写了一篇很好的文章,解释了为什么永远不要处理时区。摘录:

确实,Python datetime API总是返回不知道的datetime对象,这是非常不幸的。确实,一旦您获得此对象之一,就无法知道时区是什么,因此,这些对象本身就非常“无用”。

las,即使您可以使用utcnow(),也仍然看不到时区信息,就像您发现的那样。

建议:

  • 始终使用感知datetime对象,即带有时区信息。这样可以确保您可以直接比较它们(感知datetime 对象和未感知对象是不可比较的),并将它们正确返回给用户。利用pytz具有时区对象。

  • 使用ISO 8601作为输入和输出字符串格式。用于datetime.datetime.isoformat()将时间戳返回为使用该格式格式化的字符串,其中包括时区信息。

  • 如果您需要解析包含ISO 8601格式的时间戳记的字符串,则可以依靠iso8601,它返回带有正确时区信息的时间戳记。这使得时间戳直接可比。

Julien Danjou wrote a good article explaining why you should never deal with timezones. An excerpt:

Indeed, Python datetime API always returns unaware datetime objects, which is very unfortunate. Indeed, as soon as you get one of this object, there is no way to know what the timezone is, therefore these objects are pretty “useless” on their own.

Alas, even though you may use utcnow(), you still won’t see the timezone info, as you discovered.

Recommendations:

  • Always use aware datetime objects, i.e. with timezone information. That makes sure you can compare them directly (aware and unaware datetime objects are not comparable) and will return them correctly to users. Leverage pytz to have timezone objects.

  • Use ISO 8601 as the input and output string format. Use datetime.datetime.isoformat() to return timestamps as string formatted using that format, which includes the timezone information.

  • If you need to parse strings containing ISO 8601 formatted timestamps, you can rely on iso8601, which returns timestamps with correct timezone information. This makes timestamps directly comparable.


回答 5

timezone在Python 3.2+中添加信息

import datetime

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

To add timezone information in Python 3.2+

import datetime

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

回答 6

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]
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]

回答 7

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

UTC dates don’t need any timezone info since they’re UTC, which by definition means that they have no offset.