[英]Python daylight savings time
如何檢查夏令時是否有效?
您可以使用time.localtime
並查看返回值中的tm_isdst
標志。
>>> import time
>>> time.localtime()
(2010, 5, 21, 21, 48, 51, 4, 141, 0)
>>> _.tm_isdst
0
使用time.localtime()
,您可以在任意時間詢問相同的問題,以查看 DST 是否會(或曾經)對您的當前時區生效。
如果您在筆記本電腦上運行代碼,則接受的答案很好,但大多數 Python 應用程序都在使用 UTC 作為本地時間的服務器上運行,因此根據接受的答案,它們永遠不會處於夏令時。
第二個問題是不同地區在不同的日期和時間實施夏令時。 因此,即使您有一個明確的時間,例如datetime.utcnow()
,它也可能是一個時區的夏令時,但不是另一個時區。
我們可以做的最好的事情是判斷給定時間是否發生在特定時區的 DST 期間,我能找到的最佳方法已經由pytz localize
函數實現,我們可以使用它來得到一個很好的答案它適用於我們的筆記本電腦和服務器。
import pytz
from datetime import datetime
def is_dst(dt=None, timezone="UTC"):
if dt is None:
dt = datetime.utcnow()
timezone = pytz.timezone(timezone)
timezone_aware_date = timezone.localize(dt, is_dst=None)
return timezone_aware_date.tzinfo._dst.seconds != 0
一些例子
>>> is_dst() # it is never DST in UTC
False
>>> is_dst(datetime(2019, 1, 1), timezone="US/Pacific")
False
>>> is_dst(datetime(2019, 4, 1), timezone="US/Pacific")
True
>>> is_dst(datetime(2019, 3, 10, 2), timezone="US/Pacific")
NonExistentTimeError
>>> is_dst(datetime(2019, 11, 3, 1), timezone="US/Pacific")
AmbiguousTimeError
在我們的is_dst
函數中,我們指定is_dst=None
作為timezone.localize
的參數,這將導致無意義時間拋出錯誤。 您可以使用is_dst=False
忽略這些錯誤並在這些時間返回False
。
假設您想在datetime
執行此操作
使用pytz
使其具有時區意識,然后檢查其dst
屬性:
import datetime
import pytz
def is_dst(dt,timeZone):
aware_dt = timeZone.localize(dt)
return aware_dt.dst() != datetime.timedelta(0,0)
timeZone = pytz.timezone("Europe/London")
dt = datetime.datetime(2019,8,2)
is_dst(dt,timeZone)
True
dt = datetime.datetime(2019,2,2)
is_dst(dt,timeZone)
False
擴展上面@Greg Hewgill 的答案,加上處理本地時區(在pip install tzlocal
幫助下),您會得到:
import time
from datetime import datetime, timedelta
from tzlocal import get_localzone
def to_local(dt):
"""From any timezone to local datetime - also cope with DST"""
localtime = time.localtime()
if localtime.tm_isdst:
utctime = time.gmtime()
hours_delta = timedelta(hours=(localtime.tm_hour - utctime.tm_hour))
dt = dt - hours_delta
return dt.replace(tzinfo=get_localzone())
以上都沒有幫助我,所以我找到了自己的解決方法。
我與https://gist.github.com/dpapathanasiou/09bd2885813038d7d3eb 中實現的邏輯有關,雖然仍然存在問題,但顯然在現實生活中不起作用:(
目前我在以色列,這里我們在月底移動時鍾,而在澳大利亞,他們已經移動了時鍾。 對於Asia/Jerusalem
和Australia/Sydney
所有代碼都返回True
。
最終我使用了一個外部 3rd 方 API - https://worldtimeapi.org/ - 通過它我分析了utc_offset
是否為 11 小時(而不是 10:05)。
from requests import get as Get
is_dst = True
try:
tz_check = Get('https://worldtimeapi.org/api/timezone/Australia/Sydney')
is_dst = tz_check.json().get('utc_offset') == '+11:00'
except Exception as e:
print('!!! Error getting timezone', e)
我會將此作為對上面@mehtunguh 的答案的評論發布,但我目前的聲譽級別不允許我發表評論。
我認為省略dt
參數時編寫的is_dst
函數可能存在問題。
當dt
參數被省略時, dt
被設置為datetime.utcnow()
,它返回一個表示當前 UTC 時間的朴素日期時間。 當它傳遞給pytz.localize
,生成的本地化時間不是指定時區中的當前時間,而是與當前 UTC 時間具有相同小時、分鍾、秒的本地時間。
因此,例如,當我寫這篇文章時,它是美國/東部時區的美國東部標准時間上午 10:50,並且datetime.utcnow()
返回一個帶有hour=15
和minute=50
的日期時間值。 正如所寫的那樣,當作為is_dst(timezone='US/Eastern')
調用is_dst(timezone='US/Eastern')
, is_dst
不會檢查美國東部時間上午 10:50 的當前本地時間是否在夏令時期間,而是檢查美國東部時間下午 3:50 是否在夏令時節約時間。
我認為is_dst
也許應該編碼如下:
import datetime
import pytz
def is_dst(dt=None, timezone='UTC'):
timezone = pytz.timezone(timezone)
if dt is None:
dt = datetime.datetime.now(datetime.timezone.utc)
if dt.tzinfo is None:
tz_aware_dt = timezone.localize(dt, is_dst=None)
else:
tz_aware_dt = dt.astimezone(timezone)
return tz_aware_dt.tzinfo._dst.seconds != 0
這個版本允許通過任何一個天真的日期時間值或時區感知日期時間值作為dt
的說法。 當dt
參數被省略時,它使用當前 UTC 時間的時區感知版本,以便當它本地化到指定的時區時,它代表該時區中的當前時間。
我來自英國,這就是我處理服務器半年返回錯誤時間的方式:
import pytz
from typing import Optional
from datetime import datetime
class BritishTime(datetime):
timezone = pytz.timezone('Europe/London')
@classmethod
def dst(cls, dt: Optional[datetime] = None):
dt = dt if dt is not None else cls.now()
return cls.timezone.dst(dt)
現在,如果我使用 BritishTime 創建日期時間BritishTime
,它具有dst
方法,我可以使用它來檢查和更新時間,如下所示:
def get_correct_time(timestamp):
updated = BritishTime.fromtimestamp(timestamp)
return updated + updated.dst()
效果很好。
在 Unix 中,如果您熟悉目標時區,另一種方法是簡單地調用date
命令:
import subprocess
# First Sun of 2022-03, 00:00
subprocess.run(['date', '--date=2022-03-10 12:00:00'], env={"TZ": "US/Eastern"})
# Next Sun, 00:00
subprocess.run(['date', '--date=2022-03-10 00:00:00'], env={"TZ": "US/Eastern"})
# Ditto, 12:00
subprocess.run(['date', '--date=2022-03-13 12:00:00'], env={"TZ": "US/Eastern"})
output:
Thu Mar 10 12:00:00 EST 2022
Sun Mar 13 00:00:00 EST 2022
Sun Mar 13 12:00:00 EDT 2022
EST
用於非 DST 季節, EDT
用於 DST。 無論如何,夏令時/非夏令時之間的過渡期真的很棘手。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.