如何检查夏令时是否有效?
7 回答
您可以使用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
以上都没有帮助我,所以我找到了自己的解决方法。
我与https://gist.github.com/dpapathanasiou/09bd2885813038d7d3eb中实现的逻辑有关,虽然仍然存在问题,但它显然在现实生活中不起作用:(
目前我在以色列,我们在月底移动时钟,而在澳大利亚,他们已经移动了时钟。和的所有代码True
都返回。Asia/Jerusalem
Australia/Sydney
最终,我使用了一个外部 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 答案的评论发布,但我目前的声誉水平不允许我发表评论。
我认为省略参数is_dst
时编写的函数可能存在问题。dt
dt
省略参数时,dt
设置为datetime.utcnow()
返回表示当前 UTC 时间的原始日期时间。当它传递给pytz.localize
时,生成的本地化时间不是指定时区的当前时间,而是与当前 UTC 时间具有相同时、分、秒的本地时间。
因此,例如,当我写这篇文章时,它是美国/东部时区的美国东部标准时间上午 10:50,并datetime.utcnow()
返回一个带有hour=15
and的日期时间值minute=50
。正如所写,当调用 as 时is_dst(timezone='US/Eastern')
,is_dst
不检查当前当地时间上午 10:50 EST 是否在夏令时,它正在检查下午 3:50 EST 是否在夏令时。
我认为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 时间的时区感知版本,因此当它本地化到指定时区时,它代表该时区的当前时间。
扩展上面的@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())
我来自英国,这就是我处理服务器半年返回错误时间的方式:
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)
现在,如果我创建一个 datetime 对象BritishTime
,它具有dst
我可以用来检查和更新时间的方法,如下所示:
def get_correct_time(timestamp):
updated = BritishTime.fromtimestamp(timestamp)
return updated + updated.dst()
效果很好。