Python 夏令时
Posted
技术标签:
【中文标题】Python 夏令时【英文标题】:Python daylight savings time 【发布时间】:2011-02-22 06:53:55 【问题描述】:如何检查夏令时是否有效?
【问题讨论】:
【参考方案1】:您可以使用time.localtime
并查看返回值中的tm_isdst
标志。
>>> import time
>>> time.localtime()
(2010, 5, 21, 21, 48, 51, 4, 141, 0)
>>> _.tm_isdst
0
使用time.localtime()
,您可以在任意时间询问相同的问题,以查看 DST 是否对您当前的时区有效。
【讨论】:
使用 time.daylight 属性可能会更清楚一点。如果您当前的时区有 DST,它将返回非零结果。 @brian buck:不过这不一样。对于给定的时区,time.daylight
是恒定的,因为日光区要么存在,要么不存在。另一方面,tm_isdst
标志反映给定时间是否在在 DST 开始和结束日期内。
这种对time.daylight
的混淆似乎是一个更大的问题:bugs.python.org/issue7229。
应该是_.tm_isdst > 0
(-1
值是可能的)。
啊!我讨厌 Python 问题的这类答案,因为它是一个命令行示例,并没有说明(对我而言)如何将其放入函数中。 (我尝试 time.localtime().tm_isdst 的天真努力没有奏效。)所以我将进一步研究并增加答案。【参考方案2】:
如果您在笔记本电脑上运行代码,则接受的答案很好,但大多数 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
次。
【讨论】:
我遇到了一个错误,因为 tzinfo 没有属性_dst
。
@otocan 随时分享您运行的代码、python 版本以及其他可能相关的内容。
我得到 AttributeError: 'str' object has no attribute 'tzinfo' in is_dst timezone_aware_date = timezone.localize(dt, is_dst=None) File "C:\Applicazioni_Tommaso\Phyton\lib\site-packages \pytz\tzinfo.py",第 317 行,如果 dt.tzinfo 不是 None:AttributeError: 'str' object has no attribute 'tzinfo'
@Tms91 dt 应该是日期时间,而不是字符串。您可以通过使用datetime.strptime
解析字符串来创建日期时间对象【参考方案3】:
假设您想在 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
【讨论】:
我真的不喜欢不需要的东西,比如 True 和 False 周围的括号,但是整个 if 语句也不需要,只需返回比较。 我认为 if/else 有助于一目了然地理解逻辑,但基本上你是对的。【参考方案4】:以上都没有帮助我,所以我找到了自己的解决方法。
我与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)
我同意这是一个私人案例,但我希望这可以帮助某人:)
【讨论】:
谢谢,帮助了很多人不要重新发明***【参考方案5】:我会将此作为对上述@mehtunguh 答案的评论发布,但我目前的声誉级别不允许我发表评论。
我认为is_dst
函数在省略dt
参数时可能存在问题。
当省略 dt
参数时,dt
设置为 datetime.utcnow()
,它返回一个表示当前 UTC 时间的 naive 日期时间。将其传递给pytz.localize
时,生成的本地化时间不是指定时区的当前 时间,而是具有相同小时、分钟的本地时间,第二,作为当前的UTC时间。
因此,例如,当我写这篇文章时,它是美国/东部时区的美国东部标准时间上午 10:50,datetime.utcnow()
返回带有hour=15
和minute=50
的日期时间值。正如所写,当以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
此版本允许传递 naive 日期时间值或 时区感知 日期时间值作为 @ 987654334@ 参数。当 dt
参数被省略时,它使用当前 UTC 时间的时区感知版本,因此当它本地化到指定时区时,它代表该时区的当前时间。
【讨论】:
【参考方案6】:扩展上面@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())
【讨论】:
【参考方案7】:我来自英国,这就是我处理服务器半年返回错误时间的方式:
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
创建一个日期时间对象,它具有dst
方法,我可以使用它来检查和更新时间,如下所示:
def get_correct_time(timestamp):
updated = BritishTime.fromtimestamp(timestamp)
return updated + updated.dst()
效果很好。
【讨论】:
以上是关于Python 夏令时的主要内容,如果未能解决你的问题,请参考以下文章
在使用利用夏令时的 Python 时区时,应该传递啥 tzinfo?
如何从 Unix 纪元时间转换并在 Python 中考虑夏令时?