99 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			99 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
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())
 |