Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make Python respond to Windows timezone changes

When Python is running under Windows, time.localtime does not report the correct time if the timezone is changed during the life time of the Python instance. Under Linux, time.tzset can always been run to alleviate problems like this, but there appears to be no equivalent in Windows.

Is there a way to fix this without doing something absurd like, oh, I don't know...

#!/bin/env python
real_localtime = eval(subprocess.Popen(
    ["python","-c", "import time;repr(time.localtime())"],
    stdout=subprocess.PIPE).communicate()[0])
like image 207
Eric Pruitt Avatar asked Dec 05 '10 20:12

Eric Pruitt


3 Answers

A more rational solution is to use Kernel32's GetLocalTime with pywin32 or ctypes. Any time zone changes are reflected immediately.

import ctypes
class SYSTEMTIME(ctypes.Structure):
    _fields_ = [
        ('wYear', ctypes.c_int16),
        ('wMonth', ctypes.c_int16),
        ('wDayOfWeek', ctypes.c_int16),
        ('wDay', ctypes.c_int16),
        ('wHour', ctypes.c_int16),
        ('wMinute', ctypes.c_int16),
        ('wSecond', ctypes.c_int16),
        ('wMilliseconds', ctypes.c_int16)]

SystemTime = SYSTEMTIME()
lpSystemTime = ctypes.pointer(SystemTime)
ctypes.windll.kernel32.GetLocalTime(lpSystemTime)
print SystemTime.wHour, SystemTime.wMinute 
like image 148
Eric Pruitt Avatar answered Sep 28 '22 10:09

Eric Pruitt


No, this can't be fixed without doing what you did. It is a bit absurd, but if you need the correct time zone in Windows and it has changed during the program's execution, it must be done.

This probably isn't a bug (the documentation is very clear that the tzset() function is only available on Unix). It's more likely a weakness in Windows that prevents the Python programmers from implementing tzset() under it. You can make a request for a feature enhancement, but it's been this way since Python 2.3 (7 years), so it's unlikely it will actually get implemented.

like image 32
Rafe Kettler Avatar answered Sep 28 '22 11:09

Rafe Kettler


The bottom line is that with VC ver 6, tzset() does not work properly. However with VC ver 8 tzset() does work now (I think it may be working in ver 7 also, but I don't have that version to check with).

So all that has to happen now is to enable HAVE_WORKING_TZSET in the source code and re-compile (and test).

In my experience, all the needs of functions for different settings of TZ need to have a working tzset(). You must call tzset() any time you change C Lang TZ var -or- Windows TIME_ZONE_INFORMATION. This was not possible in VC ver 6 and that is why HAVE_WORKING_TZSET is not enabled (but should now be for at least VC ver 8 and up).

BTW. For all the date/time stuff I do, I always have a SetUtcTime() and UnsetUtcTime() which sets TZ to GMT and calls tzset() accordingly. I also have functions to temp set to another timezone as well. This is the ONLY way to do it properly! In many years of experience, I can say anything else is trouble. And calendar.timegm() is not correct. Use tzset().

Here is proof it is now working (so go bug author to fix the windows code):

(I typed this from another computer, so hopefully no spelling errors, but it is the point that I making, not the code).


NOTE: ALL BELOW IS PYTHON (I am calling C Lang from python's ctype interface) NOTE: Because I am setting TZ via DLL boundary here and thread local and all that crap, it cannot be used as a work-around. Must re-enable HAVE_WORKING_TZSET.

import time
from ctypes import *

dTime = time.time ()
nTime = int (dTime)
intTime = c_int (nTime)

print time.ctime (dTime)
print c_char_p (cdll.msvcrt.ctime (addressof (intTime))).value

-> ... 21:02:40 ... (python)
-> ... 21:02:40 ... (C lang)

cdll.msvcrt._putenv ('TZ=GMT')
cdll.msvcrt._tzset ()

(normally time.tzset() would be called and also calling inittimezone () to update python's timezone variables as well)

print time.ctime (dTime)
print c_char_p (cdll.msvcrt.ctime (addressof (intTime))).value

-> ... 21:02:40 ... (python)
-> ... 11:02:40 ... (C lang) <- the underlying VC ver 8 is working now!

(so if HAVE_WORKING_TZSET defined for (ver 8 and up) you would get this:)

-> ... 11:02:40 ... (python)
-> ... 11:02:40 ... (C lang)


Just check the source code to see what I mean.

I checked this with the latest python '2.0' series: 2.7.2 just now.

like image 39
Ron Lentjes Avatar answered Sep 28 '22 10:09

Ron Lentjes