1

When I run the line

time.strptime("2012-06-01 12:00:00 "+time.strftime("%Z"), "%Y-%m-%d %H:%M:%S %Z")

it creates a struct for me but the flag tm_isdst is wrong. At the first of June DST was active but no matter what date I enter the tm_isdst flag is always set to what it is in localtime() right now. I need to know if DST was active or not on the date I enter.

jfs
  • 399,953
  • 195
  • 994
  • 1,670

2 Answers2

3

First of all, don't include time.strftime('%Z') in your format. You're telling it your current GMT offset (including daylight saving being off) and it's [probably] using that to set tm_isdst.

Without that, you should get a struct with tm_isdst=-1:

>>> time1 = time.strptime("2012-06-01 12:00:00", "%Y-%m-%d %H:%M:%S")
>>> time1
time.struct_time(tm_year=2012, tm_mon=6, tm_mday=1, tm_hour=12, tm_min=0,
tm_sec=0, tm_wday=4, tm_yday=153, tm_isdst=-1)

Now, you can pass that to mktime, which will, given the -1 value, "guess" the DST value (I put "guess" in quotes because it will always be correct except for ambiguous 2AM cases). This will give the absolute time in time() format.

>>> time.mktime([previous value]) # my timezone is US Eastern
1338566400.0

Then you can call localtime with this value, and it will have a correctly set DST flag:

>>> time.localtime(1338566400).tm_isdst
1

You can also skip the strptime step and directly pass the values to mktime:

>>> time.mktime((2012,6,1,12,0,0,-1,-1,-1))
1338566400.0
Random832
  • 37,415
  • 3
  • 44
  • 63
  • here is a kicker: I need time.strftime('%Z') because the time I enter was not necessary in the same time zone as I am now. –  Nov 19 '12 at 13:38
  • 1
    I don't think the functions in the `time` module can handle times in time zones other than your own. You should use `pytz` or (if your application is single-threaded) you can set `os.environ['TZ']` to the desired timezone and call `time.tzset()`. In any case, specifying an explicit %Z offset in strptime will make it think it can tell whether it's DST from that. – Random832 Nov 19 '12 at 13:42
  • The thing is, just because you are in the same time zone does not mean you have the same local time because of dst. and vies versa. –  Nov 19 '12 at 14:00
  • @Martin I don't know what that last comment means. My point was, strptime, or any function in the time module, is not capable of handling arbitrary timezones. They're only capable of handling your current (os.environ['TZ']) timezone, which has exactly two GMT offsets, not 24 of them. – Random832 Nov 19 '12 at 14:04
  • "I need time.strftime('%Z')..." I don't understand. That gives you your system timezone. How will it know the timezone you mean? – Mikel Nov 19 '12 at 15:31
  • @Random832: a single timezone may have many UTC offsets at different times (more than two). On some systems, `time` module works correctly with such timezones i.e., `time.localtime(ts) - time.gmtime(ts)` may be different for different `ts` (POSIX timestamp). Assuming that there are only two offsets `-time.timezone` and `-time.altzone` may lead to [bugs](http://bugs.python.org/issue1647654) – jfs Apr 16 '14 at 23:11
  • @J.F.Sebastian I can't think of any systems where strptime supports more than two offsets/abbreviations. I don't see how they could, since tm_isdst can only have two (other than -1) values, and tzname only has two abbreviations. And regardless, my point is that it can't support arbitrary _other_ timezones. – Random832 Apr 17 '14 at 15:05
  • you: _"your **current** (os.environ['TZ']) **timezone**, which has **exactly two** GMT offsets, not 24 of them."_ me: _"a **single timezone** may have many UTC offsets at different times (**more than two**)"_. – jfs Apr 17 '14 at 16:10
0

Your question is equivalent to how to convert a local time given as a string to a local time with the local timezone info attached:

from datetime import datetime
from pytz.exceptions import InvalidTimeError # $ pip install pytz
from tzlocal import get_localzone # $ pip install tzlocal

naive_dt = datetime.strptime("2012-06-01 12:00:00", "%Y-%m-%d %H:%M:%S")
local_tz = get_localzone()
try:
    local_dt = local_tz.localize(naive_dt, is_dst=None)
except InvalidTimeError as e:
    print("can't determine whether DST is active, reason: %s" % (e,))
else:
    assert local_dt.dst() is not None
    print("DST is %sactive" % ("" if local_dt.dst() else "not ",))

It uses Olson tz database (pytz module) and therefore:

  • it works for past dates when UTC offset may have been different for reasons unrelated to DST.
  • it detects ambiguous or non-existing local times when DST can't be determined
  • it works on Windows and *nix (tzlocal module)

Note: mktime()-based solution shown in @Random832'a answer:

import time

isdst = time.localtime(time.mktime(naive_dt.timetuple())).tm_isdst > 0
  • it may provide a wrong result silently for a date in the past if OS doesn't provide its own historical timezone database
  • it may provide a wrong result silently for ambiguous or non-existent local times (during DST transitions)
Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670