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

Posted

技术标签:

【中文标题】如果日期是进行 DST(夏令时)更改的实际日期,有没有办法在 Python 中推断?【英文标题】:Is there a way to infer in Python if a date is the actual day in which the DST (Daylight Saving Time) change is made? 【发布时间】:2021-11-27 16:24:28 【问题描述】:

我想在 Python 中推断日期是否是一年中由于 DST(夏令时)而改变小时的实际日期。

使用库pytz,您可以本地化日期时间,并正确完成实际的 DST 更改。此外,库datetime 的方法dst() 允许您推断实际日期是在夏季还是冬季(example)。但是,我想推断 DST 更改的实际日期。

具体来说,我需要一个函数(例如is_dst_change(date, timezone)),它接收日期并仅在一年中确实有小时变化的那些日子返回True。例如:

import pytz
import datetime

def is_dst_change(day, timezone):
    # Localize
    loc_day = pytz.timezone(timezone).localize(day)

    # Pseudocode: Infer if a date is the actual day in which the dst hour change is made
    if loc_day is dst_change_day:
        return True
    else:
        return False

# In the timezone 'Europe/Madrid', the days in which the DST change is made in 2021 are 28/03/2021 and 31/10/2021
is_dst_change(day=datetime.datetime(year=2021, month=3, day=28), timezone = 'Europe/Madrid')  # This should return True
is_dst_change(day=datetime.datetime(year=2021, month=10, day=31), timezone = 'Europe/Madrid')  # This should return True
is_dst_change(day=datetime.datetime(year=2021, month=2, day=1), timezone = 'Europe/Madrid')  # This should return False
is_dst_change(day=datetime.datetime(year=2021, month=7, day=1), timezone = 'Europe/Madrid')  # This should return False

因此,在上面的示例中,函数 is_dst_change(day, timezone='Europe/Madrid') 将返回 True 的仅有的 2021 天是 2021 年 3 月 28 日和 2021 年 10 月 31 日。对于 2021 年的其余日子,它必须返回 False。有没有办法用 Python 来推断?

【问题讨论】:

亚利桑那州和新墨西哥州处于同一时区,但亚利桑那州不会更改为夏令时。 @Barmar 我认为这可以通过使用[Country]/[City] 时区标识符来缓解,不是吗?与使用更广泛的仅限时区的标识符相反,例如 EST/EDTPST/PDT? @esqew 没错,我没有想到这种情况。 @Barmar 你必须在这里使用IANA time zone name @esqew 缩写,如 EST/EDT、PST/PDT 不是地理意义上的时区,它们只是告诉您某些时区在特定时间段内的 UTC 偏移量那一年。而且很多都是模棱两可的,比如搜索BST。 【参考方案1】:

如果今天的 UTC 偏移量与明天的不同,那么今天是 DST 更改。

def is_dst_change(day: datetime.datetime, timezone):
    # Override time to midnight
    day = day.replace(hour=0, minute=0, second=0, microsecond=0)
    tz = pytz.timezone(timezone)
    return(tz.utcoffset(day+datetime.timedelta(days=1)) != 
            tz.utcoffset(day))

“今天”在此代码中定义为午夜到午夜。

【讨论】:

打败我! Repl.it demo 我认为这可能是确定这一点的最平衡的方法,除非pytz OOTB 提供了超优化的is_dst_change-esque 函数。 如果day 是一个日期时间对象并且小时属性是 DST 更改之后,我认为这不会给出正确的结果。您可能希望标准化为日期。【参考方案2】:

您可以使用datetime.dst()(UTC 偏移量的变化不一定是 DST 转换):

from datetime import datetime, time, timedelta
from zoneinfo import ZoneInfo # Python 3.9+

def is_date_of_DSTtransition(dt: datetime, zone: str) -> bool:
    """
    check if the date part of a datetime object falls on the date
    of a DST transition.
    """
    _d = datetime.combine(dt.date(), time.min).replace(tzinfo=ZoneInfo(zone))
    return _d.dst() != (_d+timedelta(1)).dst()

例如对于 tz Europe/Berlin:

for d in range(366):
    if is_date_of_DSTtransition(datetime(2021, 1, 1) + timedelta(d), "Europe/Berlin"):
        print((datetime(2021, 1, 1) + timedelta(d)).date())
# 2021-03-28
# 2021-10-31

注意:我在这里使用zoneinfo 而不是pytz;对于遗留代码,有一个pytz deprecation shim。无论如何,这是一个pytz 版本(需要额外的normalize):

import pytz
def is_date_of_DSTtransition(dt: datetime, zone: str) -> bool:
    _d = pytz.timezone(zone).localize(datetime.combine(dt.date(), time.min))
    return _d.dst() != pytz.timezone(zone).normalize(_d+timedelta(1)).dst()

【讨论】:

以上是关于如果日期是进行 DST(夏令时)更改的实际日期,有没有办法在 Python 中推断?的主要内容,如果未能解决你的问题,请参考以下文章

在 DST 更改发生时将字符串解析为日期

获取任何时区的 DST 开始和结束日期

确定夏令时 (DST) 在 Java 中是不是在指定日期处于活动状态

Joda-Time、夏令时更改和日期时间解析

在指定时区导入日期时间,忽略夏令时

在 Pandas 日期时间列中标记夏令时 (DST) 小时