| from __future__ import annotations |
| |
| try: |
| import winreg |
| except ImportError: |
| winreg = None |
| |
| import datetime |
| from typing import Any, Dict, cast |
| |
| from babel.core import get_global |
| from babel.localtime._helpers import _get_tzinfo_or_raise |
| |
| # When building the cldr data on windows this module gets imported. |
| # Because at that point there is no global.dat yet this call will |
| # fail. We want to catch it down in that case then and just assume |
| # the mapping was empty. |
| try: |
| tz_names: dict[str, str] = cast(Dict[str, str], get_global('windows_zone_mapping')) |
| except RuntimeError: |
| tz_names = {} |
| |
| |
| def valuestodict(key) -> dict[str, Any]: |
| """Convert a registry key's values to a dictionary.""" |
| dict = {} |
| size = winreg.QueryInfoKey(key)[1] |
| for i in range(size): |
| data = winreg.EnumValue(key, i) |
| dict[data[0]] = data[1] |
| return dict |
| |
| |
| def get_localzone_name() -> str: |
| # Windows is special. It has unique time zone names (in several |
| # meanings of the word) available, but unfortunately, they can be |
| # translated to the language of the operating system, so we need to |
| # do a backwards lookup, by going through all time zones and see which |
| # one matches. |
| handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) |
| |
| TZLOCALKEYNAME = r'SYSTEM\CurrentControlSet\Control\TimeZoneInformation' |
| localtz = winreg.OpenKey(handle, TZLOCALKEYNAME) |
| keyvalues = valuestodict(localtz) |
| localtz.Close() |
| if 'TimeZoneKeyName' in keyvalues: |
| # Windows 7 (and Vista?) |
| |
| # For some reason this returns a string with loads of NUL bytes at |
| # least on some systems. I don't know if this is a bug somewhere, I |
| # just work around it. |
| tzkeyname = keyvalues['TimeZoneKeyName'].split('\x00', 1)[0] |
| else: |
| # Windows 2000 or XP |
| |
| # This is the localized name: |
| tzwin = keyvalues['StandardName'] |
| |
| # Open the list of timezones to look up the real name: |
| TZKEYNAME = r'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones' |
| tzkey = winreg.OpenKey(handle, TZKEYNAME) |
| |
| # Now, match this value to Time Zone information |
| tzkeyname = None |
| for i in range(winreg.QueryInfoKey(tzkey)[0]): |
| subkey = winreg.EnumKey(tzkey, i) |
| sub = winreg.OpenKey(tzkey, subkey) |
| data = valuestodict(sub) |
| sub.Close() |
| if data.get('Std', None) == tzwin: |
| tzkeyname = subkey |
| break |
| |
| tzkey.Close() |
| handle.Close() |
| |
| if tzkeyname is None: |
| raise LookupError('Can not find Windows timezone configuration') |
| |
| timezone = tz_names.get(tzkeyname) |
| if timezone is None: |
| # Nope, that didn't work. Try adding 'Standard Time', |
| # it seems to work a lot of times: |
| timezone = tz_names.get(f"{tzkeyname} Standard Time") |
| |
| # Return what we have. |
| if timezone is None: |
| raise LookupError(f"Can not find timezone {tzkeyname}") |
| |
| return timezone |
| |
| |
| def _get_localzone() -> datetime.tzinfo: |
| if winreg is None: |
| raise LookupError( |
| 'Runtime support not available') |
| |
| return _get_tzinfo_or_raise(get_localzone_name()) |