summaryrefslogtreecommitdiffstats
path: root/pendulum/tz/local_timezone.py
diff options
context:
space:
mode:
Diffstat (limited to 'pendulum/tz/local_timezone.py')
-rw-r--r--pendulum/tz/local_timezone.py260
1 files changed, 0 insertions, 260 deletions
diff --git a/pendulum/tz/local_timezone.py b/pendulum/tz/local_timezone.py
deleted file mode 100644
index 41cf81b..0000000
--- a/pendulum/tz/local_timezone.py
+++ /dev/null
@@ -1,260 +0,0 @@
-from __future__ import annotations
-
-import contextlib
-import os
-import re
-import sys
-
-from contextlib import contextmanager
-from typing import Iterator
-from typing import cast
-
-from pendulum.tz.exceptions import InvalidTimezone
-from pendulum.tz.timezone import FixedTimezone
-from pendulum.tz.timezone import Timezone
-
-if sys.platform == "win32":
- try:
- import _winreg as winreg
- except (ImportError, AttributeError):
- import winreg
-
-_mock_local_timezone = None
-_local_timezone = None
-
-
-def get_local_timezone() -> Timezone | FixedTimezone:
- global _local_timezone
-
- if _mock_local_timezone is not None:
- return _mock_local_timezone
-
- if _local_timezone is None:
- tz = _get_system_timezone()
-
- _local_timezone = tz
-
- return _local_timezone
-
-
-def set_local_timezone(mock: str | Timezone | None = None) -> None:
- global _mock_local_timezone
-
- _mock_local_timezone = mock
-
-
-@contextmanager
-def test_local_timezone(mock: Timezone) -> Iterator[None]:
- set_local_timezone(mock)
-
- yield
-
- set_local_timezone()
-
-
-def _get_system_timezone() -> Timezone:
- if sys.platform == "win32":
- return _get_windows_timezone()
- elif "darwin" in sys.platform:
- return _get_darwin_timezone()
-
- return _get_unix_timezone()
-
-
-if sys.platform == "win32":
-
- def _get_windows_timezone() -> Timezone:
- from pendulum.tz.data.windows import windows_timezones
-
- # 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)
-
- tz_local_key_name = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation"
- localtz = winreg.OpenKey(handle, tz_local_key_name)
-
- timezone_info = {}
- size = winreg.QueryInfoKey(localtz)[1]
- for i in range(size):
- data = winreg.EnumValue(localtz, i)
- timezone_info[data[0]] = data[1]
-
- localtz.Close()
-
- if "TimeZoneKeyName" in timezone_info:
- # 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 = timezone_info["TimeZoneKeyName"].split("\x00", 1)[0]
- else:
- # Windows 2000 or XP
-
- # This is the localized name:
- tzwin = timezone_info["StandardName"]
-
- # Open the list of timezones to look up the real name:
- tz_key_name = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones"
- tzkey = winreg.OpenKey(handle, tz_key_name)
-
- # 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)
-
- info = {}
- size = winreg.QueryInfoKey(sub)[1]
- for i in range(size):
- data = winreg.EnumValue(sub, i)
- info[data[0]] = data[1]
-
- sub.Close()
- with contextlib.suppress(KeyError):
- # This timezone didn't have proper configuration.
- # Ignore it.
- if info["Std"] == tzwin:
- tzkeyname = subkey
- break
-
- tzkey.Close()
- handle.Close()
-
- if tzkeyname is None:
- raise LookupError("Can not find Windows timezone configuration")
-
- timezone = windows_timezones.get(tzkeyname)
- if timezone is None:
- # Nope, that didn't work. Try adding "Standard Time",
- # it seems to work a lot of times:
- timezone = windows_timezones.get(tzkeyname + " Standard Time")
-
- # Return what we have.
- if timezone is None:
- raise LookupError("Unable to find timezone " + tzkeyname)
-
- return Timezone(timezone)
-
-else:
-
- def _get_windows_timezone() -> Timezone:
- ...
-
-
-def _get_darwin_timezone() -> Timezone:
- # link will be something like /usr/share/zoneinfo/America/Los_Angeles.
- link = os.readlink("/etc/localtime")
- tzname = link[link.rfind("zoneinfo/") + 9 :]
-
- return Timezone(tzname)
-
-
-def _get_unix_timezone(_root: str = "/") -> Timezone:
- tzenv = os.environ.get("TZ")
- if tzenv:
- with contextlib.suppress(ValueError):
- return _tz_from_env(tzenv)
-
- # Now look for distribution specific configuration files
- # that contain the timezone name.
- tzpath = os.path.join(_root, "etc/timezone")
- if os.path.isfile(tzpath):
- with open(tzpath, "rb") as tzfile:
- tzfile_data = tzfile.read()
-
- # Issue #3 was that /etc/timezone was a zoneinfo file.
- # That's a misconfiguration, but we need to handle it gracefully:
- if tzfile_data[:5] != b"TZif2":
- etctz = tzfile_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 Timezone(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:
- zone_re = re.compile(r'\s*ZONE\s*=\s*"')
- timezone_re = re.compile(r'\s*TIMEZONE\s*=\s*"')
- end_re = re.compile('"')
-
- for filename in ("etc/sysconfig/clock", "etc/conf.d/clock"):
- tzpath = os.path.join(_root, filename)
- if not os.path.isfile(tzpath):
- continue
-
- with open(tzpath) as tzfile:
- data = tzfile.readlines()
-
- for line in data:
- # Look for the ZONE= setting.
- match = zone_re.match(line)
- if match is None:
- # No ZONE= setting. Look for the TIMEZONE= setting.
- match = timezone_re.match(line)
-
- if match is not None:
- # Some setting existed
- line = line[match.end() :]
- etctz = line[
- : cast(
- re.Match, end_re.search(line) # type: ignore[type-arg]
- ).start()
- ]
-
- parts = list(reversed(etctz.replace(" ", "_").split(os.path.sep)))
- tzpath_parts: list[str] = []
- while parts:
- tzpath_parts.insert(0, parts.pop(0))
-
- with contextlib.suppress(InvalidTimezone):
- return Timezone(os.path.join(*tzpath_parts))
-
- # systemd distributions use symlinks that include the zone name,
- # see manpage of localtime(5) and timedatectl(1)
- tzpath = os.path.join(_root, "etc", "localtime")
- if os.path.isfile(tzpath) and os.path.islink(tzpath):
- parts = list(
- reversed(os.path.realpath(tzpath).replace(" ", "_").split(os.path.sep))
- )
- tzpath_parts: list[str] = [] # type: ignore[no-redef]
- while parts:
- tzpath_parts.insert(0, parts.pop(0))
- with contextlib.suppress(InvalidTimezone):
- return Timezone(os.path.join(*tzpath_parts))
-
- # 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.isfile(tzpath):
- continue
-
- with open(tzpath, "rb") as f:
- return cast(Timezone, Timezone.from_file(f))
-
- raise RuntimeError("Unable to find any timezone configuration")
-
-
-def _tz_from_env(tzenv: str) -> Timezone:
- if tzenv[0] == ":":
- tzenv = tzenv[1:]
-
- # TZ specifies a file
- if os.path.isfile(tzenv):
- with open(tzenv, "rb") as f:
- return cast(Timezone, Timezone.from_file(f))
-
- # TZ specifies a zoneinfo zone.
- try:
- return Timezone(tzenv)
- except ValueError:
- raise