DeadCake
DeadCake

Reputation: 467

Check if Date is in Daylight Savings Time for Timezone Without pytz

For certain reasons, my employer does not want to use pip to install third party packages and wants me to use packages only hosted on trusty. Thus, I now cannot use pytz in my code. How would I go about checking if a certain date in a timezone is in DST? Here's my original code using pytz.

    import pytz
    import datetime
    ...

    target_date = datetime.datetime.strptime(arg_date, "%Y-%m-%d")
    time_zone = pytz.timezone('US/Eastern')
    dst_date = time_zone.localize(target_date, is_dst=None)
    est_hour = 24
    if bool(dst_date.dst()) is True:
        est_hour -= 4
    else:
        est_hour -= 5

Upvotes: 6

Views: 8228

Answers (4)

Nicolás Rivera
Nicolás Rivera

Reputation: 78

This simple function worked for me:

from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
def is_dst(date:str or datetime, format:str = "%Y-%m-%d", zonename:str = "Europe/Paris"):
# print("checking date", date)
if isinstance(date, str):
    date = datetime.strptime(date, format)
if date.month==3 or date.month==10:
    zone = ZoneInfo(zonename)
    date_1 = date.astimezone(zone) + timedelta(hours=1)
    date_2 = date.astimezone(zone) + timedelta(hours=3)
    # print("\t", date_1, "\n\t", date_2)
    return not date_1.utcoffset() == date_2.utcoffset()

It basically checks if there's a mismatch between the UTC-offset whenever that happens, and I added the if date.month==3 or date.month==10 so it only checks for the months that we know will have DST beforehand (e.g., March and October).

So is_dst("2023-03-26") returns True, is_dst("2023-10-29") returns also True and any other date within 2023 returns False.

Upvotes: 0

Mark Ransom
Mark Ransom

Reputation: 308520

There is a new capability starting with Python 3.9: the built-in zoneinfo module. If your OS has time zone information built in, this module will access it without needing any additional installed packages.

>>> import zoneinfo
>>> time_zone = zoneinfo.ZoneInfo('US/Eastern')
>>> dst_date = datetime.datetime(2022, 1, 1, tzinfo=time_zone)
>>> dst_date
datetime.datetime(2022, 1, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='US/Eastern'))
>>> dst_date.dst()
datetime.timedelta(0)
>>> dst_date2 = datetime.datetime(2022, 3, 15, tzinfo=time_zone)
>>> dst_date2
datetime.datetime(2022, 3, 15, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='US/Eastern'))
>>> dst_date2.dst()
datetime.timedelta(seconds=3600)

Upvotes: 4

Mark Ransom
Mark Ransom

Reputation: 308520

In the general case this is a complex problem that is not amenable to a hand-rolled solution. Relying on an external module that is vetted and maintained by someone dedicated to the task, such as pytz, is the only sane option.

However given the constraint that you're only interested in U.S. time zones, Eastern in particular, it's possible to write a simple function. It is obviously only good for the current (2016) rules, which last changed in 2007 and might change again at any time. Those rules state that DST starts on the second Sunday in March and ends on the first Sunday in November.

This code is based on my algorithm for finding a particular day of a month.

def is_dst(dt):
    if dt.year < 2007:
        raise ValueError()
    dst_start = datetime.datetime(dt.year, 3, 8, 2, 0)
    dst_start += datetime.timedelta(6 - dst_start.weekday())
    dst_end = datetime.datetime(dt.year, 11, 1, 2, 0)
    dst_end += datetime.timedelta(6 - dst_end.weekday())
    return dst_start <= dt < dst_end

Upvotes: 4

TessellatingHeckler
TessellatingHeckler

Reputation: 29048

Install pytz without using pip.

DST is arbitrary and chosen by legislation in different regions, you can't really calculate it - look at the pytz source for US/Eastern, for example, it's literally a list of hard-coded dates when DST changes for the next twenty years.

You could do that yourself, pulling the data from the same source that pytz does ( ZoneInfo / [or this link] (http://www.iana.org/time-zones) ). or from your OS implementation of tz if it has one...

but (unless it's a licensing reason) get your employer to look at the pytz source and confirm that it's acceptably harmless and approve it for use.

Upvotes: 0

Related Questions