【问题标题】:Why does datetime.datetime.utcnow() not contain timezone information?为什么 datetime.datetime.utcnow() 不包含时区信息?
【发布时间】:2011-01-20 20:32:07
【问题描述】:
datetime.datetime.utcnow()

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

我希望这将包含tzinfo

【问题讨论】:

  • 如何将字符串类型的普通iso格式日期字段转换为utc格式?

标签: python datetime


【解决方案1】:

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

【讨论】:

  • 据我从docs.python.org/library/datetime.html 得知,没有 tzinfo 的日期时间是未指定时区的日期时间。这里指定了时区,因此从逻辑上讲它应该存在。没有关联时区的日期/时间与绝对采用 UTC 的日期/时间之间存在很大差异。 (理想情况下,它们应该是不同类型的 IMO,但这是另一回事......)
  • @JonSkeet 我认为您错过了 Ignacio 的观点,即 UTC 不是时区。令人惊讶的是,当我输入此答案时,这个答案的得分为 -9...
  • @CS:好吧,Ignacio 从来没有说过......虽然严格来说 UTC 不是一个时区,但它通常被视为让生活变得相当简单(包括在 Python 中,例如 pytz.utc)。请注意,与 UTC 的偏移量未知的值与已知为 0 的值之间存在很大差异。后者是 utcnow() 应该 返回的值,IMO。根据文档,这将符合“一个有意识的对象用于表示一个不可解释的特定时刻”。
【解决方案2】:

标准 Python 库在 Python 3.2 之前不包含任何 tzinfo 类。我只能猜测原因。就我个人而言,我认为不包含 UTC 的 tzinfo 类是错误的,因为该类没有争议,足以拥有标准实现。虽然库中没有实现,但在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()

一旦你有了一个 UTC tzinfo 对象,你仍然不能将它与 utcnow 一起使用。获取当前时间作为感知日期时间对象:

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 -- Support for the IANA Time Zone Database in the Standard Library

【讨论】:

  • 先弄清楚为什么没有提供这个类(更重要的是,用于由utcnow()创建的datetime对象)...
  • @rgove,这对 Python 3 来说应该是公平的游戏。他们不应该担心向后兼容性。最近几天我读到了另一个例子——struct 模块会自动将 Unicode 转换为字节串,最终决定打破与早期 Python 3 版本的兼容性,以防止做出错误的决定。
  • 我很惊讶 Python 的 tzinfo 文档包含实现它的代码示例,但它们并没有在 datetime 本身中包含该功能! docs.python.org/2/library/datetime.html#datetime.tzinfo.fromutc
  • 此外,此处显示的示例 UTC 类几乎正是 pytz 模块的实现所包含的内容。它添加了一些有用的方法。
  • @LS 是的,pytz 是一个很好的资源。当我编辑我的答案以放入示例代码时,其他人已经提出了建议,我不想抢走他们的风头。
【解决方案3】:

这意味着它是天真的时区,所以你不能将它与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())——当本地时间不明确时,它可能会在夏令时结束过渡期间失败。

【讨论】:

  • 但是没有充分的理由让它天真时区 - 它被指定为 UTC。为什么要搜索第三方库才能正常工作?
  • 我同意;对我来说,“天真的”时代完全没有用。目前python列表上有关于将pytz添加到stdlib的讨论;问题不在于许可,而是时区数据更新如此频繁(Python 本身不能)这一事实。此外,pytz 没有以预期的方式实现 tzinfo 接口,因此如果您尝试使用 astimezone 中的某些城市时区,可能会出错。所以 datetime 不仅没有本地时区,而且 tzinfo 唯一广泛可用的实现不符合假定的标准。
  • @bobince 为什么 pytz 和标准日期时间库不适合您? Python 核心和 pytz 作为独立项目发展,降低了核心团队的后勤复杂性。是的,降低 Python 核心团队的复杂性会增加所有需要处理时区的 Python 用户的复杂性,但我相信他们做出这个决定是有充分理由的。规则“标准库没有 tzinfo 实例......”很好,因为它很简单,为什么要在这里例外?
  • u=datetime.now(pytz.utc)怎么样
  • @bain:不要使用tz.localize(datetime.now());请改用datetime.now(tz)
【解决方案4】:

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

【讨论】:

【解决方案5】:

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

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

所以,datetime.utcnow() 没有设置 tzinfo 来表示它是 UTC,但 datetime.now(datetime.timezone.utc) 确实返回 UTC 时间 tzinfo 设置。

所以你可以这样做:

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

【讨论】:

  • 首选哪个? datetime.now(timezone.utc)datetime.utcnow(timezone.utc)?
  • datetime.utcnow() 不接受任何参数。所以它必须是datetime.now(timezone.utc)
  • datetime.now() 将返回机器时间,但 datetime.utcnow() 将返回实际 UTC 时间。
  • @Babu: datetime.utcnow() 没有设置 tzinfo 来表示它是 UTC。但datetime.now(datetime.timezone.utc) 确实返回 UTC 时间 with tzinfo 设置。
  • 我认为现在这是正确的解决方案,当它已经明确 UTC 时,不需要添加外部依赖项来指定时区元数据
【解决方案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]

【讨论】:

    【解决方案7】:

    Julien Danjou 写了一篇很好的文章来解释why you should never deal with timezones。摘录:

    确实,Python 日期时间 API 总是返回未知的日期时间对象, 这是非常不幸的。确实,一旦你得到其中之一 对象,没有办法知道时区是什么,因此这些 对象本身就相当“无用”。

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

    建议:

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

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

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

    【讨论】:

    • 这是有点误导的建议。经验法则是,永远不要处理时区。始终存储和传输 tz unware utc 对象(epoch 对象)。时区应仅在 UI 中表示时计算
    • 听起来已经很符合于连的想法了。他的哪些具体建议(如上所述)具有误导性?
    【解决方案8】:

    在 Python 3.2+ 中添加timezone 信息

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

    【讨论】:

    • AttributeError: 'module' object has no attribute 'timezone' Python 2.7.13(默认,2017 年 1 月 19 日,14:48:08)
    • @MarcinOwsiany 尝试:from datetime import datetime, timezone 然后调用datetime.now(tz=timezone.utc)
    • 这是在不使用任何第三方 Python 模块(如 pytz)的情况下获取 UTC 时区感知日期时间对象的最佳方式。 |只是为了添加一件事。如果您想在不使用任何额外模块的情况下获取本地时区感知日期时间对象,则只需添加 astimezone(): d.astimezone()
    【解决方案9】:

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

    【讨论】:

      猜你喜欢
      • 2018-09-23
      • 1970-01-01
      • 2011-06-20
      • 1970-01-01
      • 2021-02-05
      • 2017-04-12
      • 1970-01-01
      • 2021-02-05
      • 1970-01-01
      相关资源
      最近更新 更多