structure saas with tools
This commit is contained in:
144
.venv/lib/python3.10/site-packages/tzlocal/win32.py
Normal file
144
.venv/lib/python3.10/site-packages/tzlocal/win32.py
Normal file
@@ -0,0 +1,144 @@
|
||||
import logging
|
||||
from datetime import datetime
|
||||
|
||||
try:
|
||||
import _winreg as winreg
|
||||
except ImportError:
|
||||
import winreg
|
||||
|
||||
import zoneinfo
|
||||
|
||||
from tzlocal import utils
|
||||
from tzlocal.windows_tz import win_tz
|
||||
|
||||
_cache_tz = None
|
||||
_cache_tz_name = None
|
||||
|
||||
log = logging.getLogger("tzlocal")
|
||||
|
||||
|
||||
def valuestodict(key):
|
||||
"""Convert a registry key's values to a dictionary."""
|
||||
result = {}
|
||||
size = winreg.QueryInfoKey(key)[1]
|
||||
for i in range(size):
|
||||
data = winreg.EnumValue(key, i)
|
||||
result[data[0]] = data[1]
|
||||
return result
|
||||
|
||||
|
||||
def _get_dst_info(tz):
|
||||
# Find the offset for when it doesn't have DST:
|
||||
dst_offset = std_offset = None
|
||||
has_dst = False
|
||||
year = datetime.now().year
|
||||
for dt in (datetime(year, 1, 1), datetime(year, 6, 1)):
|
||||
if tz.dst(dt).total_seconds() == 0.0:
|
||||
# OK, no DST during winter, get this offset
|
||||
std_offset = tz.utcoffset(dt).total_seconds()
|
||||
else:
|
||||
has_dst = True
|
||||
|
||||
return has_dst, std_offset, dst_offset
|
||||
|
||||
|
||||
def _get_localzone_name():
|
||||
# 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.
|
||||
tzenv = utils._tz_name_from_env()
|
||||
if tzenv:
|
||||
return tzenv
|
||||
|
||||
log.debug("Looking up time zone info from registry")
|
||||
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 later
|
||||
|
||||
# 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:
|
||||
# Don't support XP any longer
|
||||
raise LookupError("Can not find Windows timezone configuration")
|
||||
|
||||
timezone = win_tz.get(tzkeyname)
|
||||
if timezone is None:
|
||||
# Nope, that didn't work. Try adding "Standard Time",
|
||||
# it seems to work a lot of times:
|
||||
timezone = win_tz.get(tzkeyname + " Standard Time")
|
||||
|
||||
# Return what we have.
|
||||
if timezone is None:
|
||||
raise zoneinfo.ZoneInfoNotFoundError(tzkeyname)
|
||||
|
||||
if keyvalues.get("DynamicDaylightTimeDisabled", 0) == 1:
|
||||
# DST is disabled, so don't return the timezone name,
|
||||
# instead return Etc/GMT+offset
|
||||
|
||||
tz = zoneinfo.ZoneInfo(timezone)
|
||||
has_dst, std_offset, dst_offset = _get_dst_info(tz)
|
||||
if not has_dst:
|
||||
# The DST is turned off in the windows configuration,
|
||||
# but this timezone doesn't have DST so it doesn't matter
|
||||
return timezone
|
||||
|
||||
if std_offset is None:
|
||||
raise zoneinfo.ZoneInfoNotFoundError(
|
||||
f"{tzkeyname} claims to not have a non-DST time!?"
|
||||
)
|
||||
|
||||
if std_offset % 3600:
|
||||
# I can't convert this to an hourly offset
|
||||
raise zoneinfo.ZoneInfoNotFoundError(
|
||||
f"tzlocal can't support disabling DST in the {timezone} zone."
|
||||
)
|
||||
|
||||
# This has whole hours as offset, return it as Etc/GMT
|
||||
return f"Etc/GMT{-std_offset//3600:+.0f}"
|
||||
|
||||
return timezone
|
||||
|
||||
|
||||
def get_localzone_name() -> str:
|
||||
"""Get the zoneinfo timezone name that matches the Windows-configured timezone."""
|
||||
global _cache_tz_name
|
||||
if _cache_tz_name is None:
|
||||
_cache_tz_name = _get_localzone_name()
|
||||
|
||||
return _cache_tz_name
|
||||
|
||||
|
||||
def get_localzone() -> zoneinfo.ZoneInfo:
|
||||
"""Returns the zoneinfo-based tzinfo object that matches the Windows-configured timezone."""
|
||||
|
||||
global _cache_tz
|
||||
if _cache_tz is None:
|
||||
_cache_tz = zoneinfo.ZoneInfo(get_localzone_name())
|
||||
|
||||
if not utils._tz_name_from_env():
|
||||
# If the timezone does NOT come from a TZ environment variable,
|
||||
# verify that it's correct. If it's from the environment,
|
||||
# we accept it, this is so you can run tests with different timezones.
|
||||
utils.assert_tz_offset(_cache_tz, error=False)
|
||||
|
||||
return _cache_tz
|
||||
|
||||
|
||||
def reload_localzone() -> zoneinfo.ZoneInfo:
|
||||
"""Reload the cached localzone. You need to call this if the timezone has changed."""
|
||||
global _cache_tz
|
||||
global _cache_tz_name
|
||||
_cache_tz_name = _get_localzone_name()
|
||||
_cache_tz = zoneinfo.ZoneInfo(_cache_tz_name)
|
||||
utils.assert_tz_offset(_cache_tz, error=False)
|
||||
return _cache_tz
|
||||
Reference in New Issue
Block a user