[英]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
。
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 的回答。
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
使用時區感知 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 代碼上不可用
應該強調的是,從 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
時區中獲取時區感知日期足以使日期減法工作。
但是,如果您想要當前時區中的時區感知日期,則tzlocal
是tzlocal
的方法:
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.utc
是timezone.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.