Skip to content

Instantly share code, notes, and snippets.

@dpapathanasiou
Created August 16, 2014 15:42
Show Gist options
  • Save dpapathanasiou/09bd2885813038d7d3eb to your computer and use it in GitHub Desktop.
Save dpapathanasiou/09bd2885813038d7d3eb to your computer and use it in GitHub Desktop.
How to tell if Daylight Savings Time is in effect using Python
from datetime import datetime
import pytz
def is_dst ():
"""Determine whether or not Daylight Savings Time (DST)
is currently in effect"""
x = datetime(datetime.now().year, 1, 1, 0, 0, 0, tzinfo=pytz.timezone('US/Eastern')) # Jan 1 of this year
y = datetime.now(pytz.timezone('US/Eastern'))
# if DST is in effect, their offsets will be different
return not (y.utcoffset() == x.utcoffset())
@oqamar
Copy link

oqamar commented Nov 15, 2020

There are some peculiarities with pytz and timezones. You can read this for a quick explanation.

The script below should work. TL;DR, you should pass in the timezone to evaluate as a parameter.

from datetime import datetime, timedelta
import pytz


def is_dst(tz, datetime_to_check):
    """Determine whether or not Daylight Savings Time (DST)
    is currently in effect"""

    # Jan 1 of this year, when all tz assumed to not be in dst
    non_dst = datetime(year=datetime.now().year, month=1, day=1)
    # Make time zone aware based on tz passed in
    non_dst_tz_aware = pytz.timezone(tz).localize(non_dst)

    # if DST is in effect, their offsets will be different
    return not (non_dst_tz_aware.utcoffset() == datetime_to_check.utcoffset())

#################################################
# Test cases
#################################################

# DST in Eastern ends Nov 1, 2020 at 2 am
timezone_eastern = 'US/Eastern'
datetime_dst_eastern = pytz.timezone(timezone_eastern).localize( datetime(year=2020, month=11, day=1))
datetime_non_dst_eastern = pytz.timezone(timezone_eastern).localize(datetime(year=2020, month=11, day=2))
# should print True
print(timezone_eastern, datetime_dst_eastern, "is in dst:", is_dst(timezone_eastern, datetime_dst_eastern))
# should print False
print(timezone_eastern, datetime_non_dst_eastern, "is in dst:", is_dst(timezone_eastern, datetime_non_dst_eastern))

# DST in Jerusalem ends Oct 25, 2020 at 2 am
timezone_jerusalem = 'Asia/Jerusalem'
datetime_dst_jerusalem = pytz.timezone(timezone_jerusalem).localize(datetime(year=2020, month=10, day=25))
datetime_non_dst_jerusalem = pytz.timezone(timezone_jerusalem).localize(datetime(year=2020, month=10, day=26))
# should print True
print(timezone_jerusalem, datetime_dst_jerusalem, "is in dst:", is_dst(timezone_jerusalem, datetime_dst_jerusalem))
# should print False
print(timezone_jerusalem, datetime_non_dst_jerusalem, "is in dst:", is_dst(timezone_jerusalem, datetime_non_dst_jerusalem))

# DST in Sydney ends Oct 4, 2020 at 2 am
timezone_sydney = 'Australia/Sydney'
datetime_dst_sydney = pytz.timezone(timezone_sydney).localize(datetime(year=2020, month=10, day=4))
datetime_non_dst_sydney = pytz.timezone(timezone_sydney).localize(datetime(year=2020, month=10, day=5))
# should print True
print(timezone_sydney, datetime_dst_sydney, "is in dst:", is_dst(timezone_sydney, datetime_dst_sydney))
# should print False
print(timezone_sydney, datetime_non_dst_sydney, "is in dst:", is_dst(timezone_sydney, datetime_non_dst_sydney))

# try with your timezone and current time
timezone_local = 'US/Pacific'
# try with different values of timedelta days; 0 will give current timestamp
datetime_now = pytz.timezone(timezone_local).localize(datetime.now() - timedelta(days=0))
print(timezone_local, datetime_now, "is in dst:", is_dst(timezone_local, datetime_now))

@bernd-wechner
Copy link

bernd-wechner commented Jun 20, 2021

The script below should work. TL;DR, you should pass in the timezone to evaluate as a parameter.

Sorry @oqamar but you are mistaken and have dived into a classic Northern hemisphere bias trap. In the southern Hemisphere, this premise:

Jan 1 of this year, when all tz assumed to not be in dst

is erroneous as we have DST on Jan 1. Your test is also broken, (confirmation bias at play), because in 2020 in Sydney Oct 5 was in DST and Oct 4 was NOT:

https://www.timeanddate.com/time/change/australia/sydney?year=2020

Once you've localized a datetime in fact you can simply check it's .dst() method to see if it's zero.

Your script is easily fixed and made simpler as follows:

from datetime import datetime, timedelta
import pytz


def is_dst(when):
    '''Given the name of Timezone will attempt determine if that timezone is in Daylight Saving Time now (DST)'''
    return when.dst() != timedelta(0)

#################################################
# Test cases
#################################################


# DST in Eastern ends Nov 1, 2020 at 2 am
timezone_eastern = 'US/Eastern'
datetime_dst_eastern = pytz.timezone(timezone_eastern).localize(datetime(year=2020, month=11, day=1))
datetime_non_dst_eastern = pytz.timezone(timezone_eastern).localize(datetime(year=2020, month=11, day=2))

print(timezone_eastern, datetime_dst_eastern, "is in dst:", is_dst(datetime_dst_eastern), "should be: True")
print(timezone_eastern, datetime_non_dst_eastern, "is in dst:", is_dst(datetime_non_dst_eastern), "should be: False")

# DST in Jerusalem ends Oct 25, 2020 at 2 am
timezone_jerusalem = 'Asia/Jerusalem'
datetime_dst_jerusalem = pytz.timezone(timezone_jerusalem).localize(datetime(year=2020, month=10, day=25))
datetime_non_dst_jerusalem = pytz.timezone(timezone_jerusalem).localize(datetime(year=2020, month=10, day=26))

print(timezone_jerusalem, datetime_dst_jerusalem, "is in dst:", is_dst(datetime_dst_jerusalem), "should be: True")
print(timezone_jerusalem, datetime_non_dst_jerusalem, "is in dst:", is_dst(datetime_non_dst_jerusalem), "should be: False")

# DST in Sydney starts Oct 4, 2020 at 2 am
timezone_sydney = 'Australia/Sydney'
datetime_dst_sydney = pytz.timezone(timezone_sydney).localize(datetime(year=2020, month=10, day=5))
datetime_non_dst_sydney = pytz.timezone(timezone_sydney).localize(datetime(year=2020, month=10, day=4))

print(timezone_sydney, datetime_dst_sydney, "is in dst:", is_dst(datetime_dst_sydney), "should be: True")
print(timezone_sydney, datetime_non_dst_sydney, "is in dst:", is_dst(datetime_non_dst_sydney), "should be: False")

This passes the Sydney test ;-), producing:

US/Eastern 2020-11-01 00:00:00-04:00 is in dst: True should be: True
US/Eastern 2020-11-02 00:00:00-05:00 is in dst: False should be: False
Asia/Jerusalem 2020-10-25 00:00:00+03:00 is in dst: True should be: True
Asia/Jerusalem 2020-10-26 00:00:00+02:00 is in dst: False should be: False
Australia/Sydney 2020-10-05 00:00:00+11:00 is in dst: True should be: True
Australia/Sydney 2020-10-04 00:00:00+10:00 is in dst: False should be: False

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment