Python daylight savings time

PythonTimeDst

Python Problem Overview


How do I check if daylight saving time is in effect?

Python Solutions


Solution 1 - Python

You can use time.localtime and look at the tm_isdst flag in the return value.

>>> import time
>>> time.localtime()
(2010, 5, 21, 21, 48, 51, 4, 141, 0)
>>> _.tm_isdst
0

Using time.localtime(), you can ask the same question for any arbitrary time to see whether DST would be (or was) in effect for your current time zone.

Solution 2 - Python

The accepted answer is fine if you are running code on your laptop, but most python applications are running on a server using UTC as local time, so they will NEVER be in daylight savings time according to the accepted answer.

The second problem is that different regions implement daylight savings on different days and times. So even if you have an unambiguous time, such as datetime.utcnow(), it could be daylight savings time in one timezone but not in another.

The best we can do then, is tell whether a given time occurs during DST for a specific timezone, and the best method I can find for doing it has already been implemtend by pytz localize function and we can use it to get a pretty good answer that works both on our laptop and on a server.

import pytz

from datetime import datetime

def is_dst(dt=None, timezone="UTC"):
    if dt is None:
        dt = datetime.utcnow()
    timezone = pytz.timezone(timezone)
    timezone_aware_date = timezone.localize(dt, is_dst=None)
    return timezone_aware_date.tzinfo._dst.seconds != 0

Some examples

>>> is_dst() # it is never DST in UTC
False
>>> is_dst(datetime(2019, 1, 1), timezone="US/Pacific")
False
>>> is_dst(datetime(2019, 4, 1), timezone="US/Pacific")
True
>>> is_dst(datetime(2019, 3, 10, 2), timezone="US/Pacific")
NonExistentTimeError
>>> is_dst(datetime(2019, 11, 3, 1), timezone="US/Pacific")
AmbiguousTimeError

In our is_dst function, we specified is_dst=None as a parameter to timezone.localize, which will cause nonsense times to throw errors. You could use is_dst=False to ignore these errors and return False for those times.

Solution 3 - Python

Assuming you want to perform this on a datetime

Use pytz to make it timezone aware and then check its dst property:

import datetime
import pytz

def is_dst(dt,timeZone):
   aware_dt = timeZone.localize(dt)
   return aware_dt.dst() != datetime.timedelta(0,0)

timeZone = pytz.timezone("Europe/London")

dt = datetime.datetime(2019,8,2)
is_dst(dt,timeZone)
True

dt = datetime.datetime(2019,2,2)
is_dst(dt,timeZone)
False

Solution 4 - Python

None of the above helped me so I found my own workaround.

I relate to the logic implemented in https://gist.github.com/dpapathanasiou/09bd2885813038d7d3eb while there's still a problem, it doesn't work in real life apparently :(

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. All the codes return True for both Asia/Jerusalem and Australia/Sydney.

Eventually I used an external 3rd party API - https://worldtimeapi.org/ - by which I analyse whether the utc_offset is 11 hours (rather that 10:05).

from requests import get as Get

is_dst = True
try:
	tz_check = Get('https://worldtimeapi.org/api/timezone/Australia/Sydney')
	is_dst = tz_check.json().get('utc_offset') == '+11:00'
except Exception as e:
	print('!!! Error getting timezone', e)


I agree this is a private case, but I hope this can help someone :)

Solution 5 - Python

I would have posted this as a comment to the answer by @mehtunguh above, but my current reputation level does not allow me to comment.

I think there may be an issue with the is_dst function as written when the dt argument is omitted.

When the dt argument is omitted, dt is set to datetime.utcnow() which returns a naive datetime representing the current UTC time. When that is passed to pytz.localize, the resulting localized time is not the current time in the specified time zone, but rather the local time that has the same hour, minute, second, as the current UTC time.

So, for example, as I write this it is 10:50 AM EST in the US/Eastern time zone, and datetime.utcnow() returns a datetime value with hour=15 and minute=50. As written, when invoked as is_dst(timezone='US/Eastern'), is_dst is not checking whether the current local time of 10:50 AM EST is during daylight saving time, it is checking whether 3:50 PM EST is during daylight saving time.

I think is_dst should perhaps be coded as follows:

import datetime
import pytz

def is_dst(dt=None, timezone='UTC'):
    timezone = pytz.timezone(timezone)
    if dt is None:
        dt = datetime.datetime.now(datetime.timezone.utc)
    if dt.tzinfo is None:
        tz_aware_dt = timezone.localize(dt, is_dst=None)
    else:
        tz_aware_dt = dt.astimezone(timezone)
    return tz_aware_dt.tzinfo._dst.seconds != 0

This version allows passing either a naive datetime value or a timezone-aware datetime value as the dt argument. When the dt argument is omitted, it uses a timezone-aware version of the current UTC time so that when that gets localized to the specified timezone it represents the current time in that timezone.

Solution 6 - Python

Expanding @Greg Hewgill's answer above, plus coping with local timezone (with help of pip install tzlocal), you get:

import time
from datetime import datetime, timedelta
from tzlocal import get_localzone

def to_local(dt):
    """From any timezone to local datetime - also cope with DST"""
    localtime = time.localtime()
    if localtime.tm_isdst:
        utctime = time.gmtime()
        hours_delta = timedelta(hours=(localtime.tm_hour - utctime.tm_hour))
        dt = dt - hours_delta

    return dt.replace(tzinfo=get_localzone())

Solution 7 - Python

I'm from the UK and this is how I handled my server returning the wrong time for half the year:

import pytz
from typing import Optional
from datetime import datetime

class BritishTime(datetime):
    timezone = pytz.timezone('Europe/London')

    @classmethod
    def dst(cls, dt: Optional[datetime] = None):
        dt = dt if dt is not None else cls.now()
        return cls.timezone.dst(dt)

Now if I create a datetime object with BritishTime, it has the dst method which I can use to both check and update the time, something like this:

def get_correct_time(timestamp):
    updated = BritishTime.fromtimestamp(timestamp)
    return updated + updated.dst()

Works pretty well.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPawel FurmaniakView Question on Stackoverflow
Solution 1 - PythonGreg HewgillView Answer on Stackoverflow
Solution 2 - PythonkrethikaView Answer on Stackoverflow
Solution 3 - PythonotocanView Answer on Stackoverflow
Solution 4 - PythonEvgenyKolyakovView Answer on Stackoverflow
Solution 5 - PythonstackerView Answer on Stackoverflow
Solution 6 - PythonJose AlbanView Answer on Stackoverflow
Solution 7 - PythonnihilokView Answer on Stackoverflow