| 1 | # This code was originally contributed by Jeffrey Harris. |
|---|
| 2 | import datetime |
|---|
| 3 | import struct |
|---|
| 4 | import _winreg |
|---|
| 5 | |
|---|
| 6 | __author__ = "Jeffrey Harris & Gustavo Niemeyer <gustavo@niemeyer.net>" |
|---|
| 7 | |
|---|
| 8 | __all__ = ["tzwin", "tzwinlocal"] |
|---|
| 9 | |
|---|
| 10 | ONEWEEK = datetime.timedelta(7) |
|---|
| 11 | |
|---|
| 12 | TZKEYNAMENT = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones" |
|---|
| 13 | TZKEYNAME9X = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones" |
|---|
| 14 | TZLOCALKEYNAME = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation" |
|---|
| 15 | |
|---|
| 16 | def _settzkeyname(): |
|---|
| 17 | global TZKEYNAME |
|---|
| 18 | handle = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) |
|---|
| 19 | try: |
|---|
| 20 | _winreg.OpenKey(handle, TZKEYNAMENT).Close() |
|---|
| 21 | TZKEYNAME = TZKEYNAMENT |
|---|
| 22 | except WindowsError: |
|---|
| 23 | TZKEYNAME = TZKEYNAME9X |
|---|
| 24 | handle.Close() |
|---|
| 25 | |
|---|
| 26 | _settzkeyname() |
|---|
| 27 | |
|---|
| 28 | class tzwinbase(datetime.tzinfo): |
|---|
| 29 | """tzinfo class based on win32's timezones available in the registry.""" |
|---|
| 30 | |
|---|
| 31 | def utcoffset(self, dt): |
|---|
| 32 | if self._isdst(dt): |
|---|
| 33 | return datetime.timedelta(minutes=self._dstoffset) |
|---|
| 34 | else: |
|---|
| 35 | return datetime.timedelta(minutes=self._stdoffset) |
|---|
| 36 | |
|---|
| 37 | def dst(self, dt): |
|---|
| 38 | if self._isdst(dt): |
|---|
| 39 | minutes = self._dstoffset - self._stdoffset |
|---|
| 40 | return datetime.timedelta(minutes=minutes) |
|---|
| 41 | else: |
|---|
| 42 | return datetime.timedelta(0) |
|---|
| 43 | |
|---|
| 44 | def tzname(self, dt): |
|---|
| 45 | if self._isdst(dt): |
|---|
| 46 | return self._dstname |
|---|
| 47 | else: |
|---|
| 48 | return self._stdname |
|---|
| 49 | |
|---|
| 50 | def list(): |
|---|
| 51 | """Return a list of all time zones known to the system.""" |
|---|
| 52 | handle = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) |
|---|
| 53 | tzkey = _winreg.OpenKey(handle, TZKEYNAME) |
|---|
| 54 | result = [_winreg.EnumKey(tzkey, i) |
|---|
| 55 | for i in range(_winreg.QueryInfoKey(tzkey)[0])] |
|---|
| 56 | tzkey.Close() |
|---|
| 57 | handle.Close() |
|---|
| 58 | return result |
|---|
| 59 | list = staticmethod(list) |
|---|
| 60 | |
|---|
| 61 | def display(self): |
|---|
| 62 | return self._display |
|---|
| 63 | |
|---|
| 64 | def _isdst(self, dt): |
|---|
| 65 | dston = picknthweekday(dt.year, self._dstmonth, self._dstdayofweek, |
|---|
| 66 | self._dsthour, self._dstminute, |
|---|
| 67 | self._dstweeknumber) |
|---|
| 68 | dstoff = picknthweekday(dt.year, self._stdmonth, self._stddayofweek, |
|---|
| 69 | self._stdhour, self._stdminute, |
|---|
| 70 | self._stdweeknumber) |
|---|
| 71 | if dston < dstoff: |
|---|
| 72 | return dston <= dt.replace(tzinfo=None) < dstoff |
|---|
| 73 | else: |
|---|
| 74 | return not dstoff <= dt.replace(tzinfo=None) < dston |
|---|
| 75 | |
|---|
| 76 | |
|---|
| 77 | class tzwin(tzwinbase): |
|---|
| 78 | |
|---|
| 79 | def __init__(self, name): |
|---|
| 80 | self._name = name |
|---|
| 81 | |
|---|
| 82 | handle = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) |
|---|
| 83 | tzkey = _winreg.OpenKey(handle, "%s\%s" % (TZKEYNAME, name)) |
|---|
| 84 | keydict = valuestodict(tzkey) |
|---|
| 85 | tzkey.Close() |
|---|
| 86 | handle.Close() |
|---|
| 87 | |
|---|
| 88 | self._stdname = keydict["Std"].encode("iso-8859-1") |
|---|
| 89 | self._dstname = keydict["Dlt"].encode("iso-8859-1") |
|---|
| 90 | |
|---|
| 91 | self._display = keydict["Display"] |
|---|
| 92 | |
|---|
| 93 | # See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm |
|---|
| 94 | tup = struct.unpack("=3l16h", keydict["TZI"]) |
|---|
| 95 | self._stdoffset = -tup[0]-tup[1] # Bias + StandardBias * -1 |
|---|
| 96 | self._dstoffset = self._stdoffset-tup[2] # + DaylightBias * -1 |
|---|
| 97 | |
|---|
| 98 | (self._stdmonth, |
|---|
| 99 | self._stddayofweek, # Sunday = 0 |
|---|
| 100 | self._stdweeknumber, # Last = 5 |
|---|
| 101 | self._stdhour, |
|---|
| 102 | self._stdminute) = tup[4:9] |
|---|
| 103 | |
|---|
| 104 | (self._dstmonth, |
|---|
| 105 | self._dstdayofweek, # Sunday = 0 |
|---|
| 106 | self._dstweeknumber, # Last = 5 |
|---|
| 107 | self._dsthour, |
|---|
| 108 | self._dstminute) = tup[12:17] |
|---|
| 109 | |
|---|
| 110 | def __repr__(self): |
|---|
| 111 | return "tzwin(%s)" % repr(self._name) |
|---|
| 112 | |
|---|
| 113 | def __reduce__(self): |
|---|
| 114 | return (self.__class__, (self._name,)) |
|---|
| 115 | |
|---|
| 116 | |
|---|
| 117 | class tzwinlocal(tzwinbase): |
|---|
| 118 | |
|---|
| 119 | def __init__(self): |
|---|
| 120 | |
|---|
| 121 | handle = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) |
|---|
| 122 | |
|---|
| 123 | tzlocalkey = _winreg.OpenKey(handle, TZLOCALKEYNAME) |
|---|
| 124 | keydict = valuestodict(tzlocalkey) |
|---|
| 125 | tzlocalkey.Close() |
|---|
| 126 | |
|---|
| 127 | self._stdname = keydict["StandardName"].encode("iso-8859-1") |
|---|
| 128 | self._dstname = keydict["DaylightName"].encode("iso-8859-1") |
|---|
| 129 | |
|---|
| 130 | try: |
|---|
| 131 | tzkey = _winreg.OpenKey(handle, "%s\%s"%(TZKEYNAME, self._stdname)) |
|---|
| 132 | _keydict = valuestodict(tzkey) |
|---|
| 133 | self._display = _keydict["Display"] |
|---|
| 134 | tzkey.Close() |
|---|
| 135 | except OSError: |
|---|
| 136 | self._display = None |
|---|
| 137 | |
|---|
| 138 | handle.Close() |
|---|
| 139 | |
|---|
| 140 | self._stdoffset = -keydict["Bias"]-keydict["StandardBias"] |
|---|
| 141 | self._dstoffset = self._stdoffset-keydict["DaylightBias"] |
|---|
| 142 | |
|---|
| 143 | |
|---|
| 144 | # See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm |
|---|
| 145 | tup = struct.unpack("=8h", keydict["StandardStart"]) |
|---|
| 146 | |
|---|
| 147 | (self._stdmonth, |
|---|
| 148 | self._stddayofweek, # Sunday = 0 |
|---|
| 149 | self._stdweeknumber, # Last = 5 |
|---|
| 150 | self._stdhour, |
|---|
| 151 | self._stdminute) = tup[1:6] |
|---|
| 152 | |
|---|
| 153 | tup = struct.unpack("=8h", keydict["DaylightStart"]) |
|---|
| 154 | |
|---|
| 155 | (self._dstmonth, |
|---|
| 156 | self._dstdayofweek, # Sunday = 0 |
|---|
| 157 | self._dstweeknumber, # Last = 5 |
|---|
| 158 | self._dsthour, |
|---|
| 159 | self._dstminute) = tup[1:6] |
|---|
| 160 | |
|---|
| 161 | def __reduce__(self): |
|---|
| 162 | return (self.__class__, ()) |
|---|
| 163 | |
|---|
| 164 | def picknthweekday(year, month, dayofweek, hour, minute, whichweek): |
|---|
| 165 | """dayofweek == 0 means Sunday, whichweek 5 means last instance""" |
|---|
| 166 | first = datetime.datetime(year, month, 1, hour, minute) |
|---|
| 167 | weekdayone = first.replace(day=((dayofweek-first.isoweekday())%7+1)) |
|---|
| 168 | for n in xrange(whichweek): |
|---|
| 169 | dt = weekdayone+(whichweek-n)*ONEWEEK |
|---|
| 170 | if dt.month == month: |
|---|
| 171 | return dt |
|---|
| 172 | |
|---|
| 173 | def valuestodict(key): |
|---|
| 174 | """Convert a registry key's values to a dictionary.""" |
|---|
| 175 | dict = {} |
|---|
| 176 | size = _winreg.QueryInfoKey(key)[1] |
|---|
| 177 | for i in range(size): |
|---|
| 178 | data = _winreg.EnumValue(key, i) |
|---|
| 179 | dict[data[0]] = data[1] |
|---|
| 180 | return dict |
|---|