簡體   English   中英

如何在 Python 中獲取“時區感知”的 datetime.today() 值?

[英]How do I get a value of datetime.today() in Python that is "timezone aware"?

我試圖從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()返回的日期時間 object 並將其設置為 UTC-8?

在標准庫中,沒有跨平台的方式來創建感知時區而不創建自己的時區類。 編輯: 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:

獲取特定時區中的當前時間:

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

記得先安裝pytz

在 Python 3.2+ 中: datetime.timezone.utc

標准庫可以更輕松地將 UTC 指定為時區:

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

如果您想要一個僅使用標准庫並且在 Python 2 和 Python 3 中都可以使用的解決方案,請參閱jfs 的回答

在 Python 3.9+ 中: zoneinfo使用 IANA 時區數據庫:

在 Python 3.9 中,您可以使用標准庫指定特定的時區,使用zoneinfo ,如下所示:

>>> 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從操作系統或第一方 PyPI 包tzdata如果可用)獲取其時區數據庫。

從 Python 3.3 開始,僅使用標准庫的單行程序即可工作。 您可以使用astimezone (如johnchen902 建議的)獲取本地時區感知datetime對象:

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

這是一個適用於 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 偏移量的時區的午夜更為復雜。

構造表示當前時間的時區感知日期時間對象的另一種方法:

import datetime
import pytz

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

您可以通過運行從 PyPI 安裝pytz

$ pipenv install pytz

如果您使用的是Django ,則可以設置不支持 tz 的日期(僅限UTC )。

在 settings.py 中注釋以下行:

USE_TZ = True

使用時區感知 Python datetime.datetime.now() 中描述的 dateutil :

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

這是使用 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 代碼上不可用

pytz是一個 Python 庫,允許使用 Python 2.3 或更高版本進行准確的跨平台時區計算。

使用 stdlib,這是不可能的。

SO上看到一個類似的問題。

應該強調的是,從 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 的評論)。 請注意,有一個小警告, astimezone(None) 提供了知道日期時間,不知道 DST

這是一個使用可讀時區的解決方案,適用於 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

utc時區中獲取時區感知日期足以使日期減法工作。

但是,如果您想要當前時區中的時區感知日期,則tzlocaltzlocal的方法:

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

PS dateutil有一個類似的功能( dateutil.tz.tzlocal )。 但是,盡管共享名稱,但它具有完全不同的代碼庫,正如 JF Sebastian 所指出的那樣,這可能會產生錯誤的結果。

另一種選擇,在我看來更好,是使用Pendulum而不是pytz 考慮以下簡單代碼:

>>> import pendulum

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

要安裝 Pendulum 並查看其文檔,請轉到此處 它有大量的選項(比如簡單的 ISO8601、RFC3339 和許多其他格式支持)、更好的性能並且傾向於產生更簡單的代碼。

特別是對於非 UTC 時區:

唯一有自己方法的timezone.utctimezone.utc ,但如果需要,您可以使用timedelta & timezone並使用.replace強制使用任何UTC偏移量來timedelta timezone

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))作為時區是這里真正的靈丹妙葯,它還有許多其他有用的應用程序。

來自“howchoo”的 Tyler 寫了一篇非常棒的文章,幫助我更好地了解日期時間對象,鏈接如下

使用日期時間

本質上,我只是在我的兩個日期時間對象的末尾添加了以下內容

.replace(tzinfo=pytz.utc)

例子:

import pytz
import datetime from datetime

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

如果您在 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"))

使用如下所示的時區作為時區感知日期時間。 默認為 UTC:

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

嘗試pnp_datetime ,所有使用和返回的時間都帶有時區,並且不會導致任何偏移天真和偏移感知問題。

>>> from pnp_datetime.pnp_datetime import Pnp_Datetime
>>>
>>> Pnp_Datetime.utcnow()
datetime.datetime(2020, 6, 5, 12, 26, 18, 958779, tzinfo=<UTC>)

這個對我有用,我首先嘗試獲取UTC時間,然后根據您要設置的時區添加或減去小時數。

>>> import datetime
>>> today = datetime.datetime.utcnow()
datetime.datetime(2021, 10, 14, 8, 31, 33, 247734)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM