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())
							 |