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/JerusalemAustralia/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=15minute=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确定时间戳是不是在夏令时

在使用利用夏令时的 Python 时区时,应该传递啥 tzinfo?

如何从 Unix 纪元时间转换并在 Python 中考虑夏令时?

python time.time() 和“夏令时”

python pandas TimeStamps到夏令时的本地时间字符串

如果日期是进行 DST(夏令时)更改的实际日期,有没有办法在 Python 中推断?