-
-
Save dpapathanasiou/09bd2885813038d7d3eb to your computer and use it in GitHub Desktop.
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()) |
I fully understand and support the logic, but this doesn't work in real life :(
Currently I'm in Israel and here we move the clock in the end of the month, while in Australia they have already moved the clock.
The code gives True
for both Asia/Jerusalem
and Australia/Sydney
.
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))
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
How can we get local time zone using pytz and determine whether DST is in effect or not ?