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?
Asked Answered
H

2

5

I would like to infer in Python if a date is the actual day of the year in which the hour is changed due to DST (Daylight Saving Time).

With the library pytz you can localize a datetime and the actual DST change is correctly done. Furthermore, there is the method dst() of the library datetime that allows you to infer if an actual date is in summer or winter time (example). However, I would like to infer the actual day in which a DST change is made.

Concretely, I would need a function (for example is_dst_change(date, timezone)) that receives a date and returns True only for those days of the year that do have an hour change. For example:

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

Thus, in the above example the only days of 2021 for which the function is_dst_change(day, timezone='Europe/Madrid') will return True are 28/03/2021 and 31/10/2021. For the rest of the days of the year 2021, it must return False. Is there a way to infer this with Python?

Hasa answered 7/10, 2021 at 15:7 Comment(6)
Arizona and New Mexico are in the same timezone, but Arizona doesn't change to Daylight Savings Time.Whichever
@Whichever I think this is mitigated by using the [Country]/[City] timezone identifiers, no? As opposed to using the more broad timezone-only identifiers like EST/EDT, PST/PDT?Evincive
@Evincive That's correct, I hadn't thought of that case.Whichever
@Whichever you'll have to use IANA time zone name hereOlivann
@Evincive abbreviations like EST/EDT, PST/PDT are not time zones in a geographical sense, they just tell you UTC offsets of certain time zones during a certain part of the year. And many of them are ambiguous, just search for BST for example.Olivann
@MrFuppes Thanks for pointing that out; I had a hunch there was some detail about those I was missing in my comment.Evincive
O
4

You can make use of datetime.dst() (a change in UTC offset is not necessarily a DST transition):

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()

e.g. for 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

Note: I'm using zoneinfo here instead of pytz; for legacy code, there is a pytz deprecation shim. Here's a pytz version anyway (needs an additional 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()
Olivann answered 7/10, 2021 at 16:30 Comment(0)
A
2

If today's UTC offset is different than tomorrow's, then today is a DST change.

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))

"Today" is defined in this code as midnight to midnight.

Ange answered 7/10, 2021 at 15:28 Comment(2)
Beat me to it! Repl.it demo I think this is likely the most balanced way to determine this, barring an ultra-optimized is_dst_change-esque function being provided by pytz OOTB.Evincive
If day is a datetime object and the hour attribute is after the DST change, I think this won't give a correct result. You might want to normalize to the date.Olivann

© 2022 - 2025 — McMap. All rights reserved.