diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2023-12-17 14:36:26 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2023-12-17 14:36:33 +0000 |
commit | 665666d6f4213da8db57ebb480947b7caf1fe382 (patch) | |
tree | 0cac5d322dfe861a6de62b04fb916cef6dbe4510 /pendulum/tz | |
parent | Releasing debian version 3.0.0~a1-2. (diff) | |
download | pendulum-665666d6f4213da8db57ebb480947b7caf1fe382.tar.xz pendulum-665666d6f4213da8db57ebb480947b7caf1fe382.zip |
Merging upstream version 3.0.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'pendulum/tz')
-rw-r--r-- | pendulum/tz/__init__.py | 80 | ||||
-rw-r--r-- | pendulum/tz/data/__init__.py | 0 | ||||
-rw-r--r-- | pendulum/tz/data/windows.py | 139 | ||||
-rw-r--r-- | pendulum/tz/exceptions.py | 32 | ||||
-rw-r--r-- | pendulum/tz/local_timezone.py | 260 | ||||
-rw-r--r-- | pendulum/tz/timezone.py | 217 |
6 files changed, 0 insertions, 728 deletions
diff --git a/pendulum/tz/__init__.py b/pendulum/tz/__init__.py deleted file mode 100644 index 45c9855..0000000 --- a/pendulum/tz/__init__.py +++ /dev/null @@ -1,80 +0,0 @@ -from __future__ import annotations - -import sys - -from pendulum.tz.local_timezone import get_local_timezone -from pendulum.tz.local_timezone import set_local_timezone -from pendulum.tz.local_timezone import test_local_timezone -from pendulum.tz.timezone import UTC -from pendulum.tz.timezone import FixedTimezone -from pendulum.tz.timezone import Timezone - -if sys.version_info >= (3, 9): - from importlib import resources -else: - import importlib_resources as resources - -PRE_TRANSITION = "pre" -POST_TRANSITION = "post" -TRANSITION_ERROR = "error" - -_timezones = None - -_tz_cache: dict[int, FixedTimezone] = {} - - -def timezones() -> tuple[str, ...]: - global _timezones - - if _timezones is None: - with resources.files("tzdata").joinpath("zones").open() as f: - _timezones = tuple(tz.strip() for tz in f.readlines()) - - return _timezones - - -def timezone(name: str | int) -> Timezone | FixedTimezone: - """ - Return a Timezone instance given its name. - """ - if isinstance(name, int): - return fixed_timezone(name) - - if name.lower() == "utc": - return UTC - - return Timezone(name) - - -def fixed_timezone(offset: int) -> FixedTimezone: - """ - Return a Timezone instance given its offset in seconds. - """ - if offset in _tz_cache: - return _tz_cache[offset] - - tz = FixedTimezone(offset) - _tz_cache[offset] = tz - - return tz - - -def local_timezone() -> Timezone | FixedTimezone: - """ - Return the local timezone. - """ - return get_local_timezone() - - -__all__ = [ - "UTC", - "Timezone", - "FixedTimezone", - "set_local_timezone", - "get_local_timezone", - "test_local_timezone", - "timezone", - "fixed_timezone", - "local_timezone", - "timezones", -] diff --git a/pendulum/tz/data/__init__.py b/pendulum/tz/data/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/pendulum/tz/data/__init__.py +++ /dev/null diff --git a/pendulum/tz/data/windows.py b/pendulum/tz/data/windows.py deleted file mode 100644 index 65aa6c3..0000000 --- a/pendulum/tz/data/windows.py +++ /dev/null @@ -1,139 +0,0 @@ -from __future__ import annotations - -windows_timezones = { - "AUS Central Standard Time": "Australia/Darwin", - "AUS Eastern Standard Time": "Australia/Sydney", - "Afghanistan Standard Time": "Asia/Kabul", - "Alaskan Standard Time": "America/Anchorage", - "Aleutian Standard Time": "America/Adak", - "Altai Standard Time": "Asia/Barnaul", - "Arab Standard Time": "Asia/Riyadh", - "Arabian Standard Time": "Asia/Dubai", - "Arabic Standard Time": "Asia/Baghdad", - "Argentina Standard Time": "America/Buenos_Aires", - "Astrakhan Standard Time": "Europe/Astrakhan", - "Atlantic Standard Time": "America/Halifax", - "Aus Central W. Standard Time": "Australia/Eucla", - "Azerbaijan Standard Time": "Asia/Baku", - "Azores Standard Time": "Atlantic/Azores", - "Bahia Standard Time": "America/Bahia", - "Bangladesh Standard Time": "Asia/Dhaka", - "Belarus Standard Time": "Europe/Minsk", - "Bougainville Standard Time": "Pacific/Bougainville", - "Canada Central Standard Time": "America/Regina", - "Cape Verde Standard Time": "Atlantic/Cape_Verde", - "Caucasus Standard Time": "Asia/Yerevan", - "Cen. Australia Standard Time": "Australia/Adelaide", - "Central America Standard Time": "America/Guatemala", - "Central Asia Standard Time": "Asia/Almaty", - "Central Brazilian Standard Time": "America/Cuiaba", - "Central Europe Standard Time": "Europe/Budapest", - "Central European Standard Time": "Europe/Warsaw", - "Central Pacific Standard Time": "Pacific/Guadalcanal", - "Central Standard Time": "America/Chicago", - "Central Standard Time (Mexico)": "America/Mexico_City", - "Chatham Islands Standard Time": "Pacific/Chatham", - "China Standard Time": "Asia/Shanghai", - "Cuba Standard Time": "America/Havana", - "Dateline Standard Time": "Etc/GMT+12", - "E. Africa Standard Time": "Africa/Nairobi", - "E. Australia Standard Time": "Australia/Brisbane", - "E. Europe Standard Time": "Europe/Chisinau", - "E. South America Standard Time": "America/Sao_Paulo", - "Easter Island Standard Time": "Pacific/Easter", - "Eastern Standard Time": "America/New_York", - "Eastern Standard Time (Mexico)": "America/Cancun", - "Egypt Standard Time": "Africa/Cairo", - "Ekaterinburg Standard Time": "Asia/Yekaterinburg", - "FLE Standard Time": "Europe/Kiev", - "Fiji Standard Time": "Pacific/Fiji", - "GMT Standard Time": "Europe/London", - "GTB Standard Time": "Europe/Bucharest", - "Georgian Standard Time": "Asia/Tbilisi", - "Greenland Standard Time": "America/Godthab", - "Greenwich Standard Time": "Atlantic/Reykjavik", - "Haiti Standard Time": "America/Port-au-Prince", - "Hawaiian Standard Time": "Pacific/Honolulu", - "India Standard Time": "Asia/Calcutta", - "Iran Standard Time": "Asia/Tehran", - "Israel Standard Time": "Asia/Jerusalem", - "Jordan Standard Time": "Asia/Amman", - "Kaliningrad Standard Time": "Europe/Kaliningrad", - "Korea Standard Time": "Asia/Seoul", - "Libya Standard Time": "Africa/Tripoli", - "Line Islands Standard Time": "Pacific/Kiritimati", - "Lord Howe Standard Time": "Australia/Lord_Howe", - "Magadan Standard Time": "Asia/Magadan", - "Magallanes Standard Time": "America/Punta_Arenas", - "Marquesas Standard Time": "Pacific/Marquesas", - "Mauritius Standard Time": "Indian/Mauritius", - "Middle East Standard Time": "Asia/Beirut", - "Montevideo Standard Time": "America/Montevideo", - "Morocco Standard Time": "Africa/Casablanca", - "Mountain Standard Time": "America/Denver", - "Mountain Standard Time (Mexico)": "America/Chihuahua", - "Myanmar Standard Time": "Asia/Rangoon", - "N. Central Asia Standard Time": "Asia/Novosibirsk", - "Namibia Standard Time": "Africa/Windhoek", - "Nepal Standard Time": "Asia/Katmandu", - "New Zealand Standard Time": "Pacific/Auckland", - "Newfoundland Standard Time": "America/St_Johns", - "Norfolk Standard Time": "Pacific/Norfolk", - "North Asia East Standard Time": "Asia/Irkutsk", - "North Asia Standard Time": "Asia/Krasnoyarsk", - "North Korea Standard Time": "Asia/Pyongyang", - "Omsk Standard Time": "Asia/Omsk", - "Pacific SA Standard Time": "America/Santiago", - "Pacific Standard Time": "America/Los_Angeles", - "Pacific Standard Time (Mexico)": "America/Tijuana", - "Pakistan Standard Time": "Asia/Karachi", - "Paraguay Standard Time": "America/Asuncion", - "Romance Standard Time": "Europe/Paris", - "Russia Time Zone 10": "Asia/Srednekolymsk", - "Russia Time Zone 11": "Asia/Kamchatka", - "Russia Time Zone 3": "Europe/Samara", - "Russian Standard Time": "Europe/Moscow", - "SA Eastern Standard Time": "America/Cayenne", - "SA Pacific Standard Time": "America/Bogota", - "SA Western Standard Time": "America/La_Paz", - "SE Asia Standard Time": "Asia/Bangkok", - "Saint Pierre Standard Time": "America/Miquelon", - "Sakhalin Standard Time": "Asia/Sakhalin", - "Samoa Standard Time": "Pacific/Apia", - "Sao Tome Standard Time": "Africa/Sao_Tome", - "Saratov Standard Time": "Europe/Saratov", - "Singapore Standard Time": "Asia/Singapore", - "South Africa Standard Time": "Africa/Johannesburg", - "Sri Lanka Standard Time": "Asia/Colombo", - "Sudan Standard Time": "Africa/Khartoum", - "Syria Standard Time": "Asia/Damascus", - "Taipei Standard Time": "Asia/Taipei", - "Tasmania Standard Time": "Australia/Hobart", - "Tocantins Standard Time": "America/Araguaina", - "Tokyo Standard Time": "Asia/Tokyo", - "Tomsk Standard Time": "Asia/Tomsk", - "Tonga Standard Time": "Pacific/Tongatapu", - "Transbaikal Standard Time": "Asia/Chita", - "Turkey Standard Time": "Europe/Istanbul", - "Turks And Caicos Standard Time": "America/Grand_Turk", - "US Eastern Standard Time": "America/Indianapolis", - "US Mountain Standard Time": "America/Phoenix", - "UTC": "Etc/GMT", - "UTC+12": "Etc/GMT-12", - "UTC+13": "Etc/GMT-13", - "UTC-02": "Etc/GMT+2", - "UTC-08": "Etc/GMT+8", - "UTC-09": "Etc/GMT+9", - "UTC-11": "Etc/GMT+11", - "Ulaanbaatar Standard Time": "Asia/Ulaanbaatar", - "Venezuela Standard Time": "America/Caracas", - "Vladivostok Standard Time": "Asia/Vladivostok", - "W. Australia Standard Time": "Australia/Perth", - "W. Central Africa Standard Time": "Africa/Lagos", - "W. Europe Standard Time": "Europe/Berlin", - "W. Mongolia Standard Time": "Asia/Hovd", - "West Asia Standard Time": "Asia/Tashkent", - "West Bank Standard Time": "Asia/Hebron", - "West Pacific Standard Time": "Pacific/Port_Moresby", - "Yakutsk Standard Time": "Asia/Yakutsk", -} diff --git a/pendulum/tz/exceptions.py b/pendulum/tz/exceptions.py deleted file mode 100644 index b8833ac..0000000 --- a/pendulum/tz/exceptions.py +++ /dev/null @@ -1,32 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from datetime import datetime - - -class TimezoneError(ValueError): - pass - - -class InvalidTimezone(TimezoneError): - pass - - -class NonExistingTime(TimezoneError): - message = "The datetime {} does not exist." - - def __init__(self, dt: datetime) -> None: - message = self.message.format(dt) - - super().__init__(message) - - -class AmbiguousTime(TimezoneError): - message = "The datetime {} is ambiguous." - - def __init__(self, dt: datetime) -> None: - message = self.message.format(dt) - - super().__init__(message) 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 diff --git a/pendulum/tz/timezone.py b/pendulum/tz/timezone.py deleted file mode 100644 index f689004..0000000 --- a/pendulum/tz/timezone.py +++ /dev/null @@ -1,217 +0,0 @@ -from __future__ import annotations - -import datetime as datetime_ - -from abc import ABC -from abc import abstractmethod -from typing import cast - -from pendulum.tz.exceptions import AmbiguousTime -from pendulum.tz.exceptions import InvalidTimezone -from pendulum.tz.exceptions import NonExistingTime -from pendulum.utils._compat import zoneinfo - -POST_TRANSITION = "post" -PRE_TRANSITION = "pre" -TRANSITION_ERROR = "error" - - -class PendulumTimezone(ABC): - @property - @abstractmethod - def name(self) -> str: - raise NotImplementedError - - @abstractmethod - def convert( - self, dt: datetime_.datetime, raise_on_unknown_times: bool = False - ) -> datetime_.datetime: - raise NotImplementedError - - @abstractmethod - def datetime( - self, - year: int, - month: int, - day: int, - hour: int = 0, - minute: int = 0, - second: int = 0, - microsecond: int = 0, - ) -> datetime_.datetime: - raise NotImplementedError - - -class Timezone(zoneinfo.ZoneInfo, PendulumTimezone): # type: ignore[misc] - """ - Represents a named timezone. - - The accepted names are those provided by the IANA time zone database. - - >>> from pendulum.tz.timezone import Timezone - >>> tz = Timezone('Europe/Paris') - """ - - def __new__(cls, key: str) -> Timezone: - try: - return cast(Timezone, super().__new__(cls, key)) - except zoneinfo.ZoneInfoNotFoundError: - raise InvalidTimezone(key) - - @property - def name(self) -> str: - return cast(str, self.key) - - def convert( - self, dt: datetime_.datetime, raise_on_unknown_times: bool = False - ) -> datetime_.datetime: - """ - Converts a datetime in the current timezone. - - If the datetime is naive, it will be normalized. - - >>> from datetime import datetime - >>> from pendulum import timezone - >>> paris = timezone('Europe/Paris') - >>> dt = datetime(2013, 3, 31, 2, 30, fold=1) - >>> in_paris = paris.convert(dt) - >>> in_paris.isoformat() - '2013-03-31T03:30:00+02:00' - - If the datetime is aware, it will be properly converted. - - >>> new_york = timezone('America/New_York') - >>> in_new_york = new_york.convert(in_paris) - >>> in_new_york.isoformat() - '2013-03-30T21:30:00-04:00' - """ - if dt.tzinfo is None: - offset_before = ( - self.utcoffset(dt.replace(fold=0)) if dt.fold else self.utcoffset(dt) - ) - offset_after = ( - self.utcoffset(dt) if dt.fold else self.utcoffset(dt.replace(fold=1)) - ) - - if offset_after > offset_before: - # Skipped time - if raise_on_unknown_times: - raise NonExistingTime(dt) - - dt += ( - (offset_after - offset_before) - if dt.fold - else (offset_before - offset_after) - ) - elif offset_before > offset_after and raise_on_unknown_times: - # Repeated time - raise AmbiguousTime(dt) - - return dt.replace(tzinfo=self) - - return dt.astimezone(self) - - def datetime( - self, - year: int, - month: int, - day: int, - hour: int = 0, - minute: int = 0, - second: int = 0, - microsecond: int = 0, - ) -> datetime_.datetime: - """ - Return a normalized datetime for the current timezone. - """ - return self.convert( - datetime_.datetime( - year, month, day, hour, minute, second, microsecond, fold=1 - ) - ) - - def __repr__(self) -> str: - return f"{self.__class__.__name__}('{self.name}')" - - -class FixedTimezone(datetime_.tzinfo, PendulumTimezone): - def __init__(self, offset: int, name: str | None = None) -> None: - sign = "-" if offset < 0 else "+" - - minutes = offset / 60 - hour, minute = divmod(abs(int(minutes)), 60) - - if not name: - name = f"{sign}{hour:02d}:{minute:02d}" - - self._name = name - self._offset = offset - self._utcoffset = datetime_.timedelta(seconds=offset) - - @property - def name(self) -> str: - return self._name - - def convert( - self, dt: datetime_.datetime, raise_on_unknown_times: bool = False - ) -> datetime_.datetime: - if dt.tzinfo is None: - return dt.__class__( - dt.year, - dt.month, - dt.day, - dt.hour, - dt.minute, - dt.second, - dt.microsecond, - tzinfo=self, - fold=0, - ) - - return dt.astimezone(self) - - def datetime( - self, - year: int, - month: int, - day: int, - hour: int = 0, - minute: int = 0, - second: int = 0, - microsecond: int = 0, - ) -> datetime_.datetime: - return self.convert( - datetime_.datetime( - year, month, day, hour, minute, second, microsecond, fold=1 - ) - ) - - @property - def offset(self) -> int: - return self._offset - - def utcoffset(self, dt: datetime_.datetime | None) -> datetime_.timedelta: - return self._utcoffset - - def dst(self, dt: datetime_.datetime | None) -> datetime_.timedelta: - return datetime_.timedelta() - - def fromutc(self, dt: datetime_.datetime) -> datetime_.datetime: - # Use the stdlib datetime's add method to avoid infinite recursion - return (datetime_.datetime.__add__(dt, self._utcoffset)).replace(tzinfo=self) - - def tzname(self, dt: datetime_.datetime | None) -> str | None: - return self._name - - def __getinitargs__(self) -> tuple[int, str]: - return self._offset, self._name - - def __repr__(self) -> str: - name = "" - if self._name: - name = f', name="{self._name}"' - - return f"{self.__class__.__name__}({self._offset}{name})" - - -UTC = Timezone("UTC") |