summaryrefslogtreecommitdiffstats
path: root/pendulum/tz
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2023-12-17 14:36:26 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2023-12-17 14:36:33 +0000
commit665666d6f4213da8db57ebb480947b7caf1fe382 (patch)
tree0cac5d322dfe861a6de62b04fb916cef6dbe4510 /pendulum/tz
parentReleasing debian version 3.0.0~a1-2. (diff)
downloadpendulum-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__.py80
-rw-r--r--pendulum/tz/data/__init__.py0
-rw-r--r--pendulum/tz/data/windows.py139
-rw-r--r--pendulum/tz/exceptions.py32
-rw-r--r--pendulum/tz/local_timezone.py260
-rw-r--r--pendulum/tz/timezone.py217
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")