1import _winreg 2import struct 3import datetime 4 5handle=_winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) 6tzparent=_winreg.OpenKey(handle, 7 "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones") 8parentsize=_winreg.QueryInfoKey(tzparent)[0] 9 10localkey=_winreg.OpenKey(handle, 11 "SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation") 12WEEKS=datetime.timedelta(7) 13 14def list_timezones(): 15 """Return a list of all time zones known to the system.""" 16 l=[] 17 for i in xrange(parentsize): 18 l.append(_winreg.EnumKey(tzparent, i)) 19 return l 20 21class win32tz(datetime.tzinfo): 22 """tzinfo class based on win32's timezones available in the registry. 23 24 >>> local = win32tz('Central Standard Time') 25 >>> oct1 = datetime.datetime(month=10, year=2004, day=1, tzinfo=local) 26 >>> dec1 = datetime.datetime(month=12, year=2004, day=1, tzinfo=local) 27 >>> oct1.dst() 28 datetime.timedelta(0, 3600) 29 >>> dec1.dst() 30 datetime.timedelta(0) 31 >>> braz = win32tz('E. South America Standard Time') 32 >>> braz.dst(oct1) 33 datetime.timedelta(0) 34 >>> braz.dst(dec1) 35 datetime.timedelta(0, 3600) 36 37 """ 38 def __init__(self, name): 39 self.data=win32tz_data(name) 40 41 def utcoffset(self, dt): 42 if self._isdst(dt): 43 return datetime.timedelta(minutes=self.data.dstoffset) 44 else: 45 return datetime.timedelta(minutes=self.data.stdoffset) 46 47 def dst(self, dt): 48 if self._isdst(dt): 49 minutes = self.data.dstoffset - self.data.stdoffset 50 return datetime.timedelta(minutes=minutes) 51 else: 52 return datetime.timedelta(0) 53 54 def tzname(self, dt): 55 if self._isdst(dt): return self.data.dstname 56 else: return self.data.stdname 57 58 def _isdst(self, dt): 59 dat=self.data 60 dston = pickNthWeekday(dt.year, dat.dstmonth, dat.dstdayofweek, 61 dat.dsthour, dat.dstminute, dat.dstweeknumber) 62 dstoff = pickNthWeekday(dt.year, dat.stdmonth, dat.stddayofweek, 63 dat.stdhour, dat.stdminute, dat.stdweeknumber) 64 if dston < dstoff: 65 if dston <= dt.replace(tzinfo=None) < dstoff: return True 66 else: return False 67 else: 68 if dstoff <= dt.replace(tzinfo=None) < dston: return False 69 else: return True 70 71 def __repr__(self): 72 return "<win32tz - {0!s}>".format(self.data.display) 73 74def pickNthWeekday(year, month, dayofweek, hour, minute, whichweek): 75 """dayofweek == 0 means Sunday, whichweek > 4 means last instance""" 76 first = datetime.datetime(year=year, month=month, hour=hour, minute=minute, 77 day=1) 78 weekdayone = first.replace(day=((dayofweek - first.isoweekday()) % 7 + 1)) 79 for n in xrange(whichweek - 1, -1, -1): 80 dt=weekdayone + n * WEEKS 81 if dt.month == month: return dt 82 83 84class win32tz_data(object): 85 """Read a registry key for a timezone, expose its contents.""" 86 87 def __init__(self, path): 88 """Load path, or if path is empty, load local time.""" 89 if path: 90 keydict=valuesToDict(_winreg.OpenKey(tzparent, path)) 91 self.display = keydict['Display'] 92 self.dstname = keydict['Dlt'] 93 self.stdname = keydict['Std'] 94 95 #see http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm 96 tup = struct.unpack('=3l16h', keydict['TZI']) 97 self.stdoffset = -tup[0]-tup[1] #Bias + StandardBias * -1 98 self.dstoffset = self.stdoffset - tup[2] # + DaylightBias * -1 99 100 offset=3 101 self.stdmonth = tup[1 + offset] 102 self.stddayofweek = tup[2 + offset] #Sunday=0 103 self.stdweeknumber = tup[3 + offset] #Last = 5 104 self.stdhour = tup[4 + offset] 105 self.stdminute = tup[5 + offset] 106 107 offset=11 108 self.dstmonth = tup[1 + offset] 109 self.dstdayofweek = tup[2 + offset] #Sunday=0 110 self.dstweeknumber = tup[3 + offset] #Last = 5 111 self.dsthour = tup[4 + offset] 112 self.dstminute = tup[5 + offset] 113 114 else: 115 keydict=valuesToDict(localkey) 116 117 self.stdname = keydict['StandardName'] 118 self.dstname = keydict['DaylightName'] 119 120 sourcekey=_winreg.OpenKey(tzparent, self.stdname) 121 self.display = valuesToDict(sourcekey)['Display'] 122 123 self.stdoffset = -keydict['Bias']-keydict['StandardBias'] 124 self.dstoffset = self.stdoffset - keydict['DaylightBias'] 125 126 #see http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm 127 tup = struct.unpack('=8h', keydict['StandardStart']) 128 129 offset=0 130 self.stdmonth = tup[1 + offset] 131 self.stddayofweek = tup[2 + offset] #Sunday=0 132 self.stdweeknumber = tup[3 + offset] #Last = 5 133 self.stdhour = tup[4 + offset] 134 self.stdminute = tup[5 + offset] 135 136 tup = struct.unpack('=8h', keydict['DaylightStart']) 137 self.dstmonth = tup[1 + offset] 138 self.dstdayofweek = tup[2 + offset] #Sunday=0 139 self.dstweeknumber = tup[3 + offset] #Last = 5 140 self.dsthour = tup[4 + offset] 141 self.dstminute = tup[5 + offset] 142 143def valuesToDict(key): 144 """Convert a registry key's values to a dictionary.""" 145 dict={} 146 size=_winreg.QueryInfoKey(key)[1] 147 for i in xrange(size): 148 dict[_winreg.EnumValue(key, i)[0]]=_winreg.EnumValue(key, i)[1] 149 return dict 150 151def _test(): 152 import win32tz, doctest 153 doctest.testmod(win32tz, verbose=0) 154 155if __name__ == '__main__': 156 _test()