done
This commit is contained in:
43
lib/python3.11/site-packages/babel/localtime/__init__.py
Normal file
43
lib/python3.11/site-packages/babel/localtime/__init__.py
Normal file
@ -0,0 +1,43 @@
|
||||
"""
|
||||
babel.localtime
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Babel specific fork of tzlocal to determine the local timezone
|
||||
of the system.
|
||||
|
||||
:copyright: (c) 2013-2025 by the Babel Team.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
import datetime
|
||||
import sys
|
||||
|
||||
if sys.platform == 'win32':
|
||||
from babel.localtime._win32 import _get_localzone
|
||||
else:
|
||||
from babel.localtime._unix import _get_localzone
|
||||
|
||||
|
||||
# TODO(3.0): the offset constants are not part of the public API
|
||||
# and should be removed
|
||||
from babel.localtime._fallback import (
|
||||
DSTDIFF, # noqa: F401
|
||||
DSTOFFSET, # noqa: F401
|
||||
STDOFFSET, # noqa: F401
|
||||
ZERO, # noqa: F401
|
||||
_FallbackLocalTimezone,
|
||||
)
|
||||
|
||||
|
||||
def get_localzone() -> datetime.tzinfo:
|
||||
"""Returns the current underlying local timezone object.
|
||||
Generally this function does not need to be used, it's a
|
||||
better idea to use the :data:`LOCALTZ` singleton instead.
|
||||
"""
|
||||
return _get_localzone()
|
||||
|
||||
|
||||
try:
|
||||
LOCALTZ = get_localzone()
|
||||
except LookupError:
|
||||
LOCALTZ = _FallbackLocalTimezone()
|
44
lib/python3.11/site-packages/babel/localtime/_fallback.py
Normal file
44
lib/python3.11/site-packages/babel/localtime/_fallback.py
Normal file
@ -0,0 +1,44 @@
|
||||
"""
|
||||
babel.localtime._fallback
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Emulated fallback local timezone when all else fails.
|
||||
|
||||
:copyright: (c) 2013-2025 by the Babel Team.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
import datetime
|
||||
import time
|
||||
|
||||
STDOFFSET = datetime.timedelta(seconds=-time.timezone)
|
||||
DSTOFFSET = datetime.timedelta(seconds=-time.altzone) if time.daylight else STDOFFSET
|
||||
|
||||
DSTDIFF = DSTOFFSET - STDOFFSET
|
||||
ZERO = datetime.timedelta(0)
|
||||
|
||||
|
||||
class _FallbackLocalTimezone(datetime.tzinfo):
|
||||
|
||||
def utcoffset(self, dt: datetime.datetime) -> datetime.timedelta:
|
||||
if self._isdst(dt):
|
||||
return DSTOFFSET
|
||||
else:
|
||||
return STDOFFSET
|
||||
|
||||
def dst(self, dt: datetime.datetime) -> datetime.timedelta:
|
||||
if self._isdst(dt):
|
||||
return DSTDIFF
|
||||
else:
|
||||
return ZERO
|
||||
|
||||
def tzname(self, dt: datetime.datetime) -> str:
|
||||
return time.tzname[self._isdst(dt)]
|
||||
|
||||
def _isdst(self, dt: datetime.datetime) -> bool:
|
||||
tt = (dt.year, dt.month, dt.day,
|
||||
dt.hour, dt.minute, dt.second,
|
||||
dt.weekday(), 0, -1)
|
||||
stamp = time.mktime(tt)
|
||||
tt = time.localtime(stamp)
|
||||
return tt.tm_isdst > 0
|
57
lib/python3.11/site-packages/babel/localtime/_helpers.py
Normal file
57
lib/python3.11/site-packages/babel/localtime/_helpers.py
Normal file
@ -0,0 +1,57 @@
|
||||
try:
|
||||
import pytz
|
||||
except ModuleNotFoundError:
|
||||
pytz = None
|
||||
|
||||
try:
|
||||
import zoneinfo
|
||||
except ModuleNotFoundError:
|
||||
zoneinfo = None
|
||||
|
||||
|
||||
def _get_tzinfo(tzenv: str):
|
||||
"""Get the tzinfo from `zoneinfo` or `pytz`
|
||||
|
||||
:param tzenv: timezone in the form of Continent/City
|
||||
:return: tzinfo object or None if not found
|
||||
"""
|
||||
if pytz:
|
||||
try:
|
||||
return pytz.timezone(tzenv)
|
||||
except pytz.UnknownTimeZoneError:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
return zoneinfo.ZoneInfo(tzenv)
|
||||
except ValueError as ve:
|
||||
# This is somewhat hacky, but since _validate_tzfile_path() doesn't
|
||||
# raise a specific error type, we'll need to check the message to be
|
||||
# one we know to be from that function.
|
||||
# If so, we pretend it meant that the TZ didn't exist, for the benefit
|
||||
# of `babel.localtime` catching the `LookupError` raised by
|
||||
# `_get_tzinfo_or_raise()`.
|
||||
# See https://github.com/python-babel/babel/issues/1092
|
||||
if str(ve).startswith("ZoneInfo keys "):
|
||||
return None
|
||||
except zoneinfo.ZoneInfoNotFoundError:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def _get_tzinfo_or_raise(tzenv: str):
|
||||
tzinfo = _get_tzinfo(tzenv)
|
||||
if tzinfo is None:
|
||||
raise LookupError(
|
||||
f"Can not find timezone {tzenv}. \n"
|
||||
"Timezone names are generally in the form `Continent/City`.",
|
||||
)
|
||||
return tzinfo
|
||||
|
||||
|
||||
def _get_tzinfo_from_file(tzfilename: str):
|
||||
with open(tzfilename, 'rb') as tzfile:
|
||||
if pytz:
|
||||
return pytz.tzfile.build_tzinfo('local', tzfile)
|
||||
else:
|
||||
return zoneinfo.ZoneInfo.from_file(tzfile)
|
104
lib/python3.11/site-packages/babel/localtime/_unix.py
Normal file
104
lib/python3.11/site-packages/babel/localtime/_unix.py
Normal file
@ -0,0 +1,104 @@
|
||||
import datetime
|
||||
import os
|
||||
import re
|
||||
|
||||
from babel.localtime._helpers import (
|
||||
_get_tzinfo,
|
||||
_get_tzinfo_from_file,
|
||||
_get_tzinfo_or_raise,
|
||||
)
|
||||
|
||||
|
||||
def _tz_from_env(tzenv: str) -> datetime.tzinfo:
|
||||
if tzenv[0] == ':':
|
||||
tzenv = tzenv[1:]
|
||||
|
||||
# TZ specifies a file
|
||||
if os.path.exists(tzenv):
|
||||
return _get_tzinfo_from_file(tzenv)
|
||||
|
||||
# TZ specifies a zoneinfo zone.
|
||||
return _get_tzinfo_or_raise(tzenv)
|
||||
|
||||
|
||||
def _get_localzone(_root: str = '/') -> datetime.tzinfo:
|
||||
"""Tries to find the local timezone configuration.
|
||||
This method prefers finding the timezone name and passing that to
|
||||
zoneinfo or pytz, over passing in the localtime file, as in the later
|
||||
case the zoneinfo name is unknown.
|
||||
The parameter _root makes the function look for files like /etc/localtime
|
||||
beneath the _root directory. This is primarily used by the tests.
|
||||
In normal usage you call the function without parameters.
|
||||
"""
|
||||
|
||||
tzenv = os.environ.get('TZ')
|
||||
if tzenv:
|
||||
return _tz_from_env(tzenv)
|
||||
|
||||
# This is actually a pretty reliable way to test for the local time
|
||||
# zone on operating systems like OS X. On OS X especially this is the
|
||||
# only one that actually works.
|
||||
try:
|
||||
link_dst = os.readlink('/etc/localtime')
|
||||
except OSError:
|
||||
pass
|
||||
else:
|
||||
pos = link_dst.find('/zoneinfo/')
|
||||
if pos >= 0:
|
||||
# On occasion, the `/etc/localtime` symlink has a double slash, e.g.
|
||||
# "/usr/share/zoneinfo//UTC", which would make `zoneinfo.ZoneInfo`
|
||||
# complain (no absolute paths allowed), and we'd end up returning
|
||||
# `None` (as a fix for #1092).
|
||||
# Instead, let's just "fix" the double slash symlink by stripping
|
||||
# leading slashes before passing the assumed zone name forward.
|
||||
zone_name = link_dst[pos + 10:].lstrip("/")
|
||||
tzinfo = _get_tzinfo(zone_name)
|
||||
if tzinfo is not None:
|
||||
return tzinfo
|
||||
|
||||
# Now look for distribution specific configuration files
|
||||
# that contain the timezone name.
|
||||
tzpath = os.path.join(_root, 'etc/timezone')
|
||||
if os.path.exists(tzpath):
|
||||
with open(tzpath, 'rb') as tzfile:
|
||||
data = tzfile.read()
|
||||
|
||||
# Issue #3 in tzlocal was that /etc/timezone was a zoneinfo file.
|
||||
# That's a misconfiguration, but we need to handle it gracefully:
|
||||
if data[:5] != b'TZif2':
|
||||
etctz = data.strip().decode()
|
||||
# Get rid of host definitions and comments:
|
||||
if ' ' in etctz:
|
||||
etctz, dummy = etctz.split(' ', 1)
|
||||
if '#' in etctz:
|
||||
etctz, dummy = etctz.split('#', 1)
|
||||
|
||||
return _get_tzinfo_or_raise(etctz.replace(' ', '_'))
|
||||
|
||||
# CentOS has a ZONE setting in /etc/sysconfig/clock,
|
||||
# OpenSUSE has a TIMEZONE setting in /etc/sysconfig/clock and
|
||||
# Gentoo has a TIMEZONE setting in /etc/conf.d/clock
|
||||
# We look through these files for a timezone:
|
||||
timezone_re = re.compile(r'\s*(TIME)?ZONE\s*=\s*"(?P<etctz>.+)"')
|
||||
|
||||
for filename in ('etc/sysconfig/clock', 'etc/conf.d/clock'):
|
||||
tzpath = os.path.join(_root, filename)
|
||||
if not os.path.exists(tzpath):
|
||||
continue
|
||||
with open(tzpath) as tzfile:
|
||||
for line in tzfile:
|
||||
match = timezone_re.match(line)
|
||||
if match is not None:
|
||||
# We found a timezone
|
||||
etctz = match.group("etctz")
|
||||
return _get_tzinfo_or_raise(etctz.replace(' ', '_'))
|
||||
|
||||
# No explicit setting existed. Use localtime
|
||||
for filename in ('etc/localtime', 'usr/local/etc/localtime'):
|
||||
tzpath = os.path.join(_root, filename)
|
||||
|
||||
if not os.path.exists(tzpath):
|
||||
continue
|
||||
return _get_tzinfo_from_file(tzpath)
|
||||
|
||||
raise LookupError('Can not find any timezone configuration')
|
98
lib/python3.11/site-packages/babel/localtime/_win32.py
Normal file
98
lib/python3.11/site-packages/babel/localtime/_win32.py
Normal file
@ -0,0 +1,98 @@
|
||||
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())
|
Reference in New Issue
Block a user