163 lines
5.6 KiB
Python
163 lines
5.6 KiB
Python
|
|
import _winreg
|
||
|
|
import struct
|
||
|
|
import datetime
|
||
|
|
|
||
|
|
handle = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
|
||
|
|
tzparent = _winreg.OpenKey(handle,
|
||
|
|
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones")
|
||
|
|
parentsize = _winreg.QueryInfoKey(tzparent)[0]
|
||
|
|
|
||
|
|
localkey = _winreg.OpenKey(handle,
|
||
|
|
"SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation")
|
||
|
|
WEEKS = datetime.timedelta(7)
|
||
|
|
|
||
|
|
|
||
|
|
def list_timezones():
|
||
|
|
"""Return a list of all time zones known to the system."""
|
||
|
|
l = []
|
||
|
|
for i in xrange(parentsize):
|
||
|
|
l.append(_winreg.EnumKey(tzparent, i))
|
||
|
|
return l
|
||
|
|
|
||
|
|
|
||
|
|
class win32tz(datetime.tzinfo):
|
||
|
|
"""tzinfo class based on win32's timezones available in the registry.
|
||
|
|
|
||
|
|
>>> local = win32tz('Central Standard Time')
|
||
|
|
>>> oct1 = datetime.datetime(month=10, year=2004, day=1, tzinfo=local)
|
||
|
|
>>> dec1 = datetime.datetime(month=12, year=2004, day=1, tzinfo=local)
|
||
|
|
>>> oct1.dst()
|
||
|
|
datetime.timedelta(0, 3600)
|
||
|
|
>>> dec1.dst()
|
||
|
|
datetime.timedelta(0)
|
||
|
|
>>> braz = win32tz('E. South America Standard Time')
|
||
|
|
>>> braz.dst(oct1)
|
||
|
|
datetime.timedelta(0)
|
||
|
|
>>> braz.dst(dec1)
|
||
|
|
datetime.timedelta(0, 3600)
|
||
|
|
"""
|
||
|
|
|
||
|
|
def __init__(self, name):
|
||
|
|
self.data = win32tz_data(name)
|
||
|
|
|
||
|
|
def utcoffset(self, dt):
|
||
|
|
if self._isdst(dt):
|
||
|
|
return datetime.timedelta(minutes=self.data.dstoffset)
|
||
|
|
else:
|
||
|
|
return datetime.timedelta(minutes=self.data.stdoffset)
|
||
|
|
|
||
|
|
def dst(self, dt):
|
||
|
|
if self._isdst(dt):
|
||
|
|
minutes = self.data.dstoffset - self.data.stdoffset
|
||
|
|
return datetime.timedelta(minutes=minutes)
|
||
|
|
else:
|
||
|
|
return datetime.timedelta(0)
|
||
|
|
|
||
|
|
def tzname(self, dt):
|
||
|
|
if self._isdst(dt):
|
||
|
|
return self.data.dstname
|
||
|
|
else:
|
||
|
|
return self.data.stdname
|
||
|
|
|
||
|
|
def _isdst(self, dt):
|
||
|
|
dat = self.data
|
||
|
|
dston = pickNthWeekday(dt.year, dat.dstmonth, dat.dstdayofweek,
|
||
|
|
dat.dsthour, dat.dstminute, dat.dstweeknumber)
|
||
|
|
dstoff = pickNthWeekday(dt.year, dat.stdmonth, dat.stddayofweek,
|
||
|
|
dat.stdhour, dat.stdminute, dat.stdweeknumber)
|
||
|
|
if dston < dstoff:
|
||
|
|
return (dston <= dt.replace(tzinfo=None) < dstoff)
|
||
|
|
else:
|
||
|
|
return not (dstoff <= dt.replace(tzinfo=None) < dston)
|
||
|
|
|
||
|
|
def __repr__(self):
|
||
|
|
return "<win32tz - {0!s}>".format(self.data.display)
|
||
|
|
|
||
|
|
|
||
|
|
def pickNthWeekday(year, month, dayofweek, hour, minute, whichweek):
|
||
|
|
"""dayofweek == 0 means Sunday, whichweek > 4 means last instance"""
|
||
|
|
first = datetime.datetime(year=year, month=month, hour=hour, minute=minute,
|
||
|
|
day=1)
|
||
|
|
weekdayone = first.replace(day=((dayofweek - first.isoweekday()) % 7 + 1))
|
||
|
|
for n in xrange(whichweek - 1, -1, -1):
|
||
|
|
dt = weekdayone + n * WEEKS
|
||
|
|
if dt.month == month:
|
||
|
|
return dt
|
||
|
|
|
||
|
|
|
||
|
|
class win32tz_data(object):
|
||
|
|
"""Read a registry key for a timezone, expose its contents."""
|
||
|
|
|
||
|
|
def __init__(self, path):
|
||
|
|
"""Load path, or if path is empty, load local time."""
|
||
|
|
if path:
|
||
|
|
keydict = valuesToDict(_winreg.OpenKey(tzparent, path))
|
||
|
|
self.display = keydict['Display']
|
||
|
|
self.dstname = keydict['Dlt']
|
||
|
|
self.stdname = keydict['Std']
|
||
|
|
|
||
|
|
#see http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm
|
||
|
|
tup = struct.unpack('=3l16h', keydict['TZI'])
|
||
|
|
self.stdoffset = -tup[0] - tup[1] # Bias + StandardBias * -1
|
||
|
|
self.dstoffset = self.stdoffset - tup[2] # + DaylightBias * -1
|
||
|
|
|
||
|
|
offset = 3
|
||
|
|
self.stdmonth = tup[1 + offset]
|
||
|
|
self.stddayofweek = tup[2 + offset] # Sunday=0
|
||
|
|
self.stdweeknumber = tup[3 + offset] # Last = 5
|
||
|
|
self.stdhour = tup[4 + offset]
|
||
|
|
self.stdminute = tup[5 + offset]
|
||
|
|
|
||
|
|
offset = 11
|
||
|
|
self.dstmonth = tup[1 + offset]
|
||
|
|
self.dstdayofweek = tup[2 + offset] # Sunday=0
|
||
|
|
self.dstweeknumber = tup[3 + offset] # Last = 5
|
||
|
|
self.dsthour = tup[4 + offset]
|
||
|
|
self.dstminute = tup[5 + offset]
|
||
|
|
|
||
|
|
else:
|
||
|
|
keydict = valuesToDict(localkey)
|
||
|
|
|
||
|
|
self.stdname = keydict['StandardName']
|
||
|
|
self.dstname = keydict['DaylightName']
|
||
|
|
|
||
|
|
sourcekey = _winreg.OpenKey(tzparent, self.stdname)
|
||
|
|
self.display = valuesToDict(sourcekey)['Display']
|
||
|
|
|
||
|
|
self.stdoffset = -keydict['Bias'] - keydict['StandardBias']
|
||
|
|
self.dstoffset = self.stdoffset - keydict['DaylightBias']
|
||
|
|
|
||
|
|
#see http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm
|
||
|
|
tup = struct.unpack('=8h', keydict['StandardStart'])
|
||
|
|
|
||
|
|
offset = 0
|
||
|
|
self.stdmonth = tup[1 + offset]
|
||
|
|
self.stddayofweek = tup[2 + offset] # Sunday=0
|
||
|
|
self.stdweeknumber = tup[3 + offset] # Last = 5
|
||
|
|
self.stdhour = tup[4 + offset]
|
||
|
|
self.stdminute = tup[5 + offset]
|
||
|
|
|
||
|
|
tup = struct.unpack('=8h', keydict['DaylightStart'])
|
||
|
|
self.dstmonth = tup[1 + offset]
|
||
|
|
self.dstdayofweek = tup[2 + offset] # Sunday=0
|
||
|
|
self.dstweeknumber = tup[3 + offset] # Last = 5
|
||
|
|
self.dsthour = tup[4 + offset]
|
||
|
|
self.dstminute = tup[5 + offset]
|
||
|
|
|
||
|
|
|
||
|
|
def valuesToDict(key):
|
||
|
|
"""Convert a registry key's values to a dictionary."""
|
||
|
|
d = {}
|
||
|
|
size = _winreg.QueryInfoKey(key)[1]
|
||
|
|
for i in xrange(size):
|
||
|
|
d[_winreg.EnumValue(key, i)[0]] = _winreg.EnumValue(key, i)[1]
|
||
|
|
return d
|
||
|
|
|
||
|
|
|
||
|
|
def _test():
|
||
|
|
import win32tz, doctest
|
||
|
|
doctest.testmod(win32tz, verbose=0)
|
||
|
|
|
||
|
|
if __name__ == '__main__':
|
||
|
|
_test()
|