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

2025-02-12 10:04:00
admin
原创
89
摘要:问题描述:我试图从 的值中减去一个日期值datetime.datetime.today()来计算某件事发生的时间。但它抱怨道:TypeError: can't subtract offset-naive and offset-aware datetimes 返回值datetime.datetime.today...

问题描述:

我试图从 的值中减去一个日期值datetime.datetime.today()来计算某件事发生的时间。但它抱怨道:

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

返回值datetime.datetime.today()似乎不是“时区感知的”,而我的其他日期值是。如何获取datetime.datetime.today()时区感知的返回值?

理想的解决方案是让它自动知道时区。

现在,它给我的是当地时间,恰好是 PST,即 UTC - 8 小时。最坏的情况是,我有没有办法手动将时区值输入到datetime返回的对象中datetime.datetime.today()并将其设置为 UTC-8?


解决方案 1:

在标准库中,如果不创建自己的时区类,则无法跨平台创建感知时区的方法。(编辑: Python 3.9zoneinfo在标准库中引入了此功能。)

在 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:

  • pytz 文档

  • 每个开发人员都应该知道的时间知识——许多实际用例的开发提示

  • 时间和时区的问题 - Computerphile – 关于使用时区的复杂性的有趣、令人大开眼界的解释(视频)

解决方案 2:

在 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 没有),则从第一方 PyPI 包(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 的回答。

解决方案 3:

获取特定时区的当前时间:

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

记得先安装pytz

解决方案 4:

从 Python 3.3 开始,仅使用标准库的单行代码就可以工作。你可以datetime使用以下命令获取本地时区感知对象astimezone(如johnchen902 所建议的):

from datetime import datetime, timezone

aware_local_now = datetime.now(timezone.utc).astimezone()

print(aware_local_now)
# 2020-03-03 09:51:38.570162+01:00

print(repr(aware_local_now))
# datetime.datetime(2020, 3, 3, 9, 51, 38, 570162, tzinfo=datetime.timezone(datetime.timedelta(0, 3600), 'CET'))

解决方案 5:

这是一个适用于 Python 2 和 3 的 stdlib 解决方案:

from datetime import datetime

now = datetime.now(utc) # Timezone-aware datetime.utcnow()
today = datetime(now.year, now.month, now.day, tzinfo=utc) # Midnight

其中today是一个感知型日期时间实例,代表 UTC 时间的开始(午夜),并且utc是一个 tzinfo 对象(示例来自文档):

from datetime import tzinfo, timedelta

ZERO = timedelta(0)

class UTC(tzinfo):
    def utcoffset(self, dt):
        return ZERO

    def tzname(self, dt):
        return "UTC"

    def dst(self, dt):
        return ZERO

utc = UTC()

相关:获取给定 UTC 时间的午夜(一天的开始)的几种方法的性能比较。注意:获取具有非固定 UTC 偏移量的时区的午夜更加复杂。

解决方案 6:

构造表示当前时间的时区感知日期时间对象的另一种方法:

import datetime
import pytz

pytz.utc.localize( datetime.datetime.utcnow() )  

您可以pytz通过运行以下命令从 PyPI 安装:

$ pipenv install pytz

解决方案 7:

如果您正在使用Django,您可以设置非 tz 感知的日期(仅UTC)。

在 settings.py 中注释以下行:

USE_TZ = True

解决方案 8:

按照 Python datetime.datetime.now() 中的说明使用具有时区意识的dateutil :

from dateutil.tz import tzlocal
# Get the current date/time with the timezone.
now = datetime.datetime.now(tzlocal())

python-dateutil要作为依赖项安装,请运行:

pip install python-dateutil

解决方案 9:

以下是使用 stdlib 生成它的一种方法:

import time
from datetime import datetime

FORMAT='%Y-%m-%dT%H:%M:%S%z'
date=datetime.strptime(time.strftime(FORMAT, time.localtime()),FORMAT)

date将存储本地日期和与 UTC 的偏移量,而不是 UTC 时区的日期,因此如果您需要确定日期是在哪个时区生成的,则可以使用此解决方案。在此示例中,在我的本地时区中:

date
datetime.datetime(2017, 8, 1, 12, 15, 44, tzinfo=datetime.timezone(datetime.timedelta(0, 7200)))

date.tzname()
'UTC+02:00'

关键是将%z指令添加到表示 FORMAT 中,以指示生成的时间结构的 UTC 偏移量。其他表示格式可以参阅 datetime 模块文档

如果您需要 UTC 时区的日期,则可以将time.localtime()替换为time.gmtime()

date=datetime.strptime(time.strftime(FORMAT, time.gmtime()),FORMAT)

date    
datetime.datetime(2017, 8, 1, 10, 23, 51, tzinfo=datetime.timezone.utc)

date.tzname()
'UTC'

编辑

这仅适用于 python3。z 指令在 python 2 _strptime.py 代码中不可用

解决方案 10:

需要强调的是,自 Python 3.6 以来,您只需要标准库即可获取表示本地时间(操作系统的设置)的时区感知日期时间对象。使用astimezone()

import datetime

datetime.datetime(2010, 12, 25, 10, 59).astimezone()
# e.g.
# datetime.datetime(2010, 12, 25, 10, 59, tzinfo=datetime.timezone(datetime.timedelta(seconds=3600), 'Mitteleuropäische Zeit'))

datetime.datetime(2010, 12, 25, 12, 59).astimezone().isoformat()
# e.g.
# '2010-12-25T12:59:00+01:00'

# I'm on CET/CEST

(参见@johnchen902 的评论)。

但请注意,有一个小警告,不要期望 timedelta 时区具有任何“DST 感知”。

解决方案 11:

pytz是一个 Python 库,允许使用 Python 2.3 或更高版本进行精确的跨平台时区计算。

使用 stdlib,这是不可能的。

请参阅SO上的类似问题。

解决方案 12:

这是一个使用可读时区并与 today() 配合使用的解决方案:

from pytz import timezone

datetime.now(timezone('Europe/Berlin'))
datetime.now(timezone('Europe/Berlin')).today()

您可以按如下方式列出所有时区:

import pytz

pytz.all_timezones
pytz.common_timezones # or

解决方案 13:

获取时区中可感知时区的日期utc足以使日期减法起作用。

但是如果您想要在当前时区中获取时区感知日期,tzlocal则可以这样做:

from tzlocal import get_localzone  # pip install tzlocal
from datetime import datetime
datetime.now(get_localzone())

PSdateutil具有类似的功能(dateutil.tz.tzlocal)。但尽管名称相同,但其代码库却完全不同,正如JF Sebastian 所指出的那样,这可能会导致错误的结果。

解决方案 14:

另一个选择,在我看来是一个更好的选择,是使用Pendulum而不是pytz。考虑以下简单代码:

>>> import pendulum

>>> dt = pendulum.now().to_iso8601_string()
>>> print (dt)
2018-03-27T13:59:49+03:00
>>>

要安装 Pendulum 并查看其文档,请转到此处。它有大量选项(如简单的 ISO8601、RFC3339 和许多其他格式支持)、更好的性能并且往往会产生更简单的代码。

解决方案 15:

特别是对于非 UTC 时区:

唯一具有自己的方法的时区是timezone.utc,但是如果需要,您可以使用timedelta&来伪造具有任何 UTC 偏移量的时区timezone,并使用 强制执行.replace

In [1]: from datetime import datetime, timezone, timedelta

In [2]: def force_timezone(dt, utc_offset=0):
   ...:     return dt.replace(tzinfo=timezone(timedelta(hours=utc_offset)))
   ...:

In [3]: dt = datetime(2011,8,15,8,15,12,0)

In [4]: str(dt)
Out[4]: '2011-08-15 08:15:12'

In [5]: str(force_timezone(dt, -8))
Out[5]: '2011-08-15 08:15:12-08:00'

使用timezone(timedelta(hours=n))时区是真正的灵丹妙药,它还有很多其他有用的应用程序。

解决方案 16:

来自“howchoo”的 Tyler 写了一篇非常棒的文章,帮助我更好地了解了 Datetime 对象,链接如下

使用日期时间

本质上,我只是在两个日期时间对象的末尾添加了以下内容

.replace(tzinfo=pytz.utc)

例子:

import pytz
import datetime from datetime

date = datetime.now().replace(tzinfo=pytz.utc)

解决方案 17:

我尝试了这里的大多数其他解决方案,但它们都不起作用。这是在 Python3.x 上有效的方法

import datetime, pytz
def get_current_datetime(timezone_str='America/Toronto'):
    utc_now = datetime.datetime.now()
    timezone = pytz.timezone(timezone_str)
    now_tz = utc_now.replace(tzinfo=pytz.utc).astimezone(timezone)
    return now_tz

解决方案 18:

如果您在 python 中获取当前时间和日期,然后在 python 中导入日期和时间、pytz 包,之后您将获得当前日期和时间,就像这样。

from datetime import datetime
import pytz
import time
str(datetime.strftime(datetime.now(pytz.utc),"%Y-%m-%d %H:%M:%S%t"))

解决方案 19:

使用如下所示的时区来实现时区感知的日期时间。默认值为 UTC:

from django.utils import timezone
today = timezone.now()

解决方案 20:

尝试pnp_datetime,所有使用和返回的时间都带有时区,并且不会导致任何偏移量无关和偏移量感知问题。

>>> from pnp_datetime.pnp_datetime import Pnp_Datetime
>>>
>>> Pnp_Datetime.utcnow()
datetime.datetime(2020, 6, 5, 12, 26, 18, 958779, tzinfo=<UTC>)
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2839  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1724  
  PLM(产品生命周期管理)软件在现代企业的产品研发、生产与管理过程中扮演着至关重要的角色。随着软件功能的日益复杂,对其进行全面、高效的测试成为确保软件质量的关键环节。自动化测试平台因其能够提高测试效率、降低人力成本、提升测试准确性等优势,在PLM软件测试中得到了广泛应用。本文将对2025年市场上8种自动化测试平台的功能...
plm系统   27  
  PLM(产品生命周期管理)系统在当今企业运营中扮演着至关重要的角色,尤其是在优化供应链协同方面。通过有效的数据对接,PLM系统能够极大提升供应链各环节的沟通效率、降低成本并提高产品质量。接下来将详细阐述如何通过7步实现数据对接,从而优化供应链协同。明确协同目标与范围在着手进行数据对接之前,明确协同目标与范围是首要任务。...
plm系统   21  
  在企业全球化发展的进程中,跨地域协同成为众多企业提升效率、整合资源的关键需求。PLM(产品生命周期管理)系统作为管理产品全生命周期信息的重要工具,如何实现高效的跨地域协同是当前面临的重要课题。随着技术的不断发展,到 2025 年将会有一系列先进的技术方案助力 PLM 系统达成这一目标。云计算技术的深度应用云计算技术为 ...
免费plm软件   25  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用