win32.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. try:
  2. import _winreg as winreg
  3. except ImportError:
  4. import winreg
  5. from tzlocal.windows_tz import win_tz
  6. import pytz
  7. _cache_tz = None
  8. def valuestodict(key):
  9. """Convert a registry key's values to a dictionary."""
  10. dict = {}
  11. size = winreg.QueryInfoKey(key)[1]
  12. for i in range(size):
  13. data = winreg.EnumValue(key, i)
  14. dict[data[0]] = data[1]
  15. return dict
  16. def get_localzone_name():
  17. # Windows is special. It has unique time zone names (in several
  18. # meanings of the word) available, but unfortunately, they can be
  19. # translated to the language of the operating system, so we need to
  20. # do a backwards lookup, by going through all time zones and see which
  21. # one matches.
  22. handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
  23. TZLOCALKEYNAME = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation"
  24. localtz = winreg.OpenKey(handle, TZLOCALKEYNAME)
  25. keyvalues = valuestodict(localtz)
  26. localtz.Close()
  27. if 'TimeZoneKeyName' in keyvalues:
  28. # Windows 7 (and Vista?)
  29. # For some reason this returns a string with loads of NUL bytes at
  30. # least on some systems. I don't know if this is a bug somewhere, I
  31. # just work around it.
  32. tzkeyname = keyvalues['TimeZoneKeyName'].split('\x00', 1)[0]
  33. else:
  34. # Windows 2000 or XP
  35. # This is the localized name:
  36. tzwin = keyvalues['StandardName']
  37. # Open the list of timezones to look up the real name:
  38. TZKEYNAME = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones"
  39. tzkey = winreg.OpenKey(handle, TZKEYNAME)
  40. # Now, match this value to Time Zone information
  41. tzkeyname = None
  42. for i in range(winreg.QueryInfoKey(tzkey)[0]):
  43. subkey = winreg.EnumKey(tzkey, i)
  44. sub = winreg.OpenKey(tzkey, subkey)
  45. data = valuestodict(sub)
  46. sub.Close()
  47. try:
  48. if data['Std'] == tzwin:
  49. tzkeyname = subkey
  50. break
  51. except KeyError:
  52. # This timezone didn't have proper configuration.
  53. # Ignore it.
  54. pass
  55. tzkey.Close()
  56. handle.Close()
  57. if tzkeyname is None:
  58. raise LookupError('Can not find Windows timezone configuration')
  59. timezone = win_tz.get(tzkeyname)
  60. if timezone is None:
  61. # Nope, that didn't work. Try adding "Standard Time",
  62. # it seems to work a lot of times:
  63. timezone = win_tz.get(tzkeyname + " Standard Time")
  64. # Return what we have.
  65. if timezone is None:
  66. raise pytz.UnknownTimeZoneError('Can not find timezone ' + tzkeyname)
  67. return timezone
  68. def get_localzone():
  69. """Returns the zoneinfo-based tzinfo object that matches the Windows-configured timezone."""
  70. global _cache_tz
  71. if _cache_tz is None:
  72. _cache_tz = pytz.timezone(get_localzone_name())
  73. return _cache_tz
  74. def reload_localzone():
  75. """Reload the cached localzone. You need to call this if the timezone has changed."""
  76. global _cache_tz
  77. _cache_tz = pytz.timezone(get_localzone_name())