tzwin.py 5.7 KB

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