codekingpro/portable-devtools
114k
1from __future__ import annotations2 3try:4 import winreg5except ImportError:6 winreg = None7 8import datetime9from typing import Any, Dict, cast10 11from babel.core import get_global12from babel.localtime._helpers import _get_tzinfo_or_raise13 14# When building the cldr data on windows this module gets imported.15# Because at that point there is no global.dat yet this call will16# fail. We want to catch it down in that case then and just assume17# the mapping was empty.18try:19 tz_names: dict[str, str] = cast(Dict[str, str], get_global('windows_zone_mapping'))20except RuntimeError:21 tz_names = {}22 23 24def valuestodict(key) -> dict[str, Any]:25 """Convert a registry key's values to a dictionary."""26 dict = {}27 size = winreg.QueryInfoKey(key)[1]28 for i in range(size):29 data = winreg.EnumValue(key, i)30 dict[data[0]] = data[1]31 return dict32 33 34def get_localzone_name() -> str:35 # Windows is special. It has unique time zone names (in several36 # meanings of the word) available, but unfortunately, they can be37 # translated to the language of the operating system, so we need to38 # do a backwards lookup, by going through all time zones and see which39 # one matches.40 handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)41 42 TZLOCALKEYNAME = r'SYSTEM\CurrentControlSet\Control\TimeZoneInformation'43 localtz = winreg.OpenKey(handle, TZLOCALKEYNAME)44 keyvalues = valuestodict(localtz)45 localtz.Close()46 if 'TimeZoneKeyName' in keyvalues:47 # Windows 7 (and Vista?)48 49 # For some reason this returns a string with loads of NUL bytes at50 # least on some systems. I don't know if this is a bug somewhere, I51 # just work around it.52 tzkeyname = keyvalues['TimeZoneKeyName'].split('\x00', 1)[0]53 else:54 # Windows 2000 or XP55 56 # This is the localized name:57 tzwin = keyvalues['StandardName']58 59 # Open the list of timezones to look up the real name:60 TZKEYNAME = r'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones'61 tzkey = winreg.OpenKey(handle, TZKEYNAME)62 63 # Now, match this value to Time Zone information64 tzkeyname = None65 for i in range(winreg.QueryInfoKey(tzkey)[0]):66 subkey = winreg.EnumKey(tzkey, i)67 sub = winreg.OpenKey(tzkey, subkey)68 data = valuestodict(sub)69 sub.Close()70 if data.get('Std', None) == tzwin:71 tzkeyname = subkey72 break73 74 tzkey.Close()75 handle.Close()76 77 if tzkeyname is None:78 raise LookupError('Can not find Windows timezone configuration')79 80 timezone = tz_names.get(tzkeyname)81 if timezone is None:82 # Nope, that didn't work. Try adding 'Standard Time',83 # it seems to work a lot of times:84 timezone = tz_names.get(f"{tzkeyname} Standard Time")85 86 # Return what we have.87 if timezone is None:88 raise LookupError(f"Can not find timezone {tzkeyname}")89 90 return timezone91 92 93def _get_localzone() -> datetime.tzinfo:94 if winreg is None:95 raise LookupError(96 'Runtime support not available')97 98 return _get_tzinfo_or_raise(get_localzone_name())99 