Revert "Update apscheduler==3.8.1"

This reverts commit 973cad264f.
This commit is contained in:
JonnyWong16 2021-11-28 13:47:49 -08:00
parent 045bfb9502
commit c0fb1dbbdc
No known key found for this signature in database
GPG key ID: B1F1F9807184697A
20 changed files with 333 additions and 1122 deletions

View file

@ -1,34 +0,0 @@
__all__ = [
"AmbiguousTimeError",
"NonExistentTimeError",
"InvalidTimeError",
"UnknownTimeZoneError",
"PytzUsageWarning",
"FixedOffset",
"UTC",
"utc",
"build_tzinfo",
"timezone",
"fixed_offset_timezone",
"wrap_zone",
]
from . import helpers
from ._exceptions import (
AmbiguousTimeError,
InvalidTimeError,
NonExistentTimeError,
PytzUsageWarning,
UnknownTimeZoneError,
)
from ._impl import (
UTC,
build_tzinfo,
fixed_offset_timezone,
timezone,
wrap_zone,
)
# Compatibility aliases
utc = UTC
FixedOffset = fixed_offset_timezone

View file

@ -1,13 +0,0 @@
import sys
_PYTZ_IMPORTED = False
def pytz_imported():
"""Detects whether or not pytz has been imported without importing pytz."""
global _PYTZ_IMPORTED
if not _PYTZ_IMPORTED and "pytz" in sys.modules:
_PYTZ_IMPORTED = True
return _PYTZ_IMPORTED

View file

@ -1,15 +0,0 @@
import sys
if sys.version_info[0] == 2:
from . import _compat_py2 as _compat_impl
else:
from . import _compat_py3 as _compat_impl
UTC = _compat_impl.UTC
get_timezone = _compat_impl.get_timezone
get_timezone_file = _compat_impl.get_timezone_file
get_fixed_offset_zone = _compat_impl.get_fixed_offset_zone
is_ambiguous = _compat_impl.is_ambiguous
is_imaginary = _compat_impl.is_imaginary
enfold = _compat_impl.enfold
get_fold = _compat_impl.get_fold

View file

@ -1,43 +0,0 @@
from datetime import timedelta
from dateutil import tz
UTC = tz.UTC
def get_timezone(key):
if not key:
raise KeyError("Unknown time zone: %s" % key)
try:
rv = tz.gettz(key)
except Exception:
rv = None
if rv is None or not isinstance(rv, (tz.tzutc, tz.tzfile)):
raise KeyError("Unknown time zone: %s" % key)
return rv
def get_timezone_file(f, key=None):
return tz.tzfile(f)
def get_fixed_offset_zone(offset):
return tz.tzoffset(None, timedelta(minutes=offset))
def is_ambiguous(dt):
return tz.datetime_ambiguous(dt)
def is_imaginary(dt):
return not tz.datetime_exists(dt)
enfold = tz.enfold
def get_fold(dt):
return getattr(dt, "fold", 0)

View file

@ -1,58 +0,0 @@
# Note: This file could use Python 3-only syntax, but at the moment this breaks
# the coverage job on Python 2. Until we make it so that coverage can ignore
# this file only on Python 2, we'll have to stick to 2/3-compatible syntax.
try:
import zoneinfo
except ImportError:
from backports import zoneinfo
import datetime
UTC = datetime.timezone.utc
def get_timezone(key):
try:
return zoneinfo.ZoneInfo(key)
except (ValueError, OSError):
# TODO: Use `from e` when this file can use Python 3 syntax
raise KeyError(key)
def get_timezone_file(f, key=None):
return zoneinfo.ZoneInfo.from_file(f, key=key)
def get_fixed_offset_zone(offset):
return datetime.timezone(datetime.timedelta(minutes=offset))
def is_imaginary(dt):
dt_rt = dt.astimezone(UTC).astimezone(dt.tzinfo)
return not (dt == dt_rt)
def is_ambiguous(dt):
if is_imaginary(dt):
return False
wall_0 = dt
wall_1 = dt.replace(fold=not dt.fold)
# Ambiguous datetimes can only exist if the offset changes, so we don't
# actually have to check whether dst() or tzname() are different.
same_offset = wall_0.utcoffset() == wall_1.utcoffset()
return not same_offset
def enfold(dt, fold=1):
if dt.fold != fold:
return dt.replace(fold=fold)
else:
return dt
def get_fold(dt):
return dt.fold

View file

@ -1,75 +0,0 @@
from ._common import pytz_imported
class PytzUsageWarning(RuntimeWarning):
"""Warning raised when accessing features specific to ``pytz``'s interface.
This warning is used to direct users of ``pytz``-specific features like the
``localize`` and ``normalize`` methods towards using the standard
``tzinfo`` interface, so that these shims can be replaced with one of the
underlying libraries they are wrapping.
"""
class UnknownTimeZoneError(KeyError):
"""Raised when no time zone is found for a specified key."""
class InvalidTimeError(Exception):
"""The base class for exceptions related to folds and gaps."""
class AmbiguousTimeError(InvalidTimeError):
"""Exception raised when ``is_dst=None`` for an ambiguous time (fold)."""
class NonExistentTimeError(InvalidTimeError):
"""Exception raised when ``is_dst=None`` for a non-existent time (gap)."""
PYTZ_BASE_ERROR_MAPPING = {}
def _make_pytz_derived_errors(
InvalidTimeError_=InvalidTimeError,
AmbiguousTimeError_=AmbiguousTimeError,
NonExistentTimeError_=NonExistentTimeError,
UnknownTimeZoneError_=UnknownTimeZoneError,
):
if PYTZ_BASE_ERROR_MAPPING or not pytz_imported():
return
import pytz
class InvalidTimeError(InvalidTimeError_, pytz.InvalidTimeError):
pass
class AmbiguousTimeError(AmbiguousTimeError_, pytz.AmbiguousTimeError):
pass
class NonExistentTimeError(
NonExistentTimeError_, pytz.NonExistentTimeError
):
pass
class UnknownTimeZoneError(
UnknownTimeZoneError_, pytz.UnknownTimeZoneError
):
pass
PYTZ_BASE_ERROR_MAPPING.update(
{
InvalidTimeError_: InvalidTimeError,
AmbiguousTimeError_: AmbiguousTimeError,
NonExistentTimeError_: NonExistentTimeError,
UnknownTimeZoneError_: UnknownTimeZoneError,
}
)
def get_exception(exc_type, msg):
_make_pytz_derived_errors()
out_exc_type = PYTZ_BASE_ERROR_MAPPING.get(exc_type, exc_type)
return out_exc_type(msg)

View file

@ -1,296 +0,0 @@
# -*- coding: utf-8 -*-
import warnings
from datetime import tzinfo
from . import _compat
from ._exceptions import (
AmbiguousTimeError,
NonExistentTimeError,
PytzUsageWarning,
UnknownTimeZoneError,
get_exception,
)
IS_DST_SENTINEL = object()
KEY_SENTINEL = object()
def timezone(key, _cache={}):
"""Builds an IANA database time zone shim.
This is the equivalent of ``pytz.timezone``.
:param key:
A valid key from the IANA time zone database.
:raises UnknownTimeZoneError:
If an unknown value is passed, this will raise an exception that can be
caught by :exc:`pytz_deprecation_shim.UnknownTimeZoneError` or
``pytz.UnknownTimeZoneError``. Like
:exc:`zoneinfo.ZoneInfoNotFoundError`, both of those are subclasses of
:exc:`KeyError`.
"""
instance = _cache.get(key, None)
if instance is None:
if len(key) == 3 and key.lower() == "utc":
instance = _cache.setdefault(key, UTC)
else:
try:
zone = _compat.get_timezone(key)
except KeyError:
raise get_exception(UnknownTimeZoneError, key)
instance = _cache.setdefault(key, wrap_zone(zone, key=key))
return instance
def fixed_offset_timezone(offset, _cache={}):
"""Builds a fixed offset time zone shim.
This is the equivalent of ``pytz.FixedOffset``. An alias is available as
``pytz_deprecation_shim.FixedOffset`` as well.
:param offset:
A fixed offset from UTC, in minutes. This must be in the range ``-1439
<= offset <= 1439``.
:raises ValueError:
For offsets whose absolute value is greater than or equal to 24 hours.
:return:
A shim time zone.
"""
if not (-1440 < offset < 1440):
raise ValueError("absolute offset is too large", offset)
instance = _cache.get(offset, None)
if instance is None:
if offset == 0:
instance = _cache.setdefault(offset, UTC)
else:
zone = _compat.get_fixed_offset_zone(offset)
instance = _cache.setdefault(offset, wrap_zone(zone, key=None))
return instance
def build_tzinfo(zone, fp):
"""Builds a shim object from a TZif file.
This is a shim for ``pytz.build_tzinfo``. Given a value to use as the zone
IANA key and a file-like object containing a valid TZif file (i.e.
conforming to :rfc:`8536`), this builds a time zone object and wraps it in
a shim class.
The argument names are chosen to match those in ``pytz.build_tzinfo``.
:param zone:
A string to be used as the time zone object's IANA key.
:param fp:
A readable file-like object emitting bytes, pointing to a valid TZif
file.
:return:
A shim time zone.
"""
zone_file = _compat.get_timezone_file(fp)
return wrap_zone(zone_file, key=zone)
def wrap_zone(tz, key=KEY_SENTINEL, _cache={}):
"""Wrap an existing time zone object in a shim class.
This is likely to be useful if you would like to work internally with
non-``pytz`` zones, but you expose an interface to callers relying on
``pytz``'s interface. It may also be useful for passing non-``pytz`` zones
to libraries expecting to use ``pytz``'s interface.
:param tz:
A :pep:`495`-compatible time zone, such as those provided by
:mod:`dateutil.tz` or :mod:`zoneinfo`.
:param key:
The value for the IANA time zone key. This is optional for ``zoneinfo``
zones, but required for ``dateutil.tz`` zones.
:return:
A shim time zone.
"""
if key is KEY_SENTINEL:
key = getattr(tz, "key", KEY_SENTINEL)
if key is KEY_SENTINEL:
raise TypeError(
"The `key` argument is required when wrapping zones that do not "
+ "have a `key` attribute."
)
instance = _cache.get((id(tz), key), None)
if instance is None:
instance = _cache.setdefault((id(tz), key), _PytzShimTimezone(tz, key))
return instance
class _PytzShimTimezone(tzinfo):
# Add instance variables for _zone and _key because this will make error
# reporting with partially-initialized _BasePytzShimTimezone objects
# work better.
_zone = None
_key = None
def __init__(self, zone, key):
self._key = key
self._zone = zone
def utcoffset(self, dt):
return self._zone.utcoffset(dt)
def dst(self, dt):
return self._zone.dst(dt)
def tzname(self, dt):
return self._zone.tzname(dt)
def fromutc(self, dt):
# The default fromutc implementation only works if tzinfo is "self"
dt_base = dt.replace(tzinfo=self._zone)
dt_out = self._zone.fromutc(dt_base)
return dt_out.replace(tzinfo=self)
def __str__(self):
if self._key is not None:
return str(self._key)
else:
return repr(self)
def __repr__(self):
return "%s(%s, %s)" % (
self.__class__.__name__,
repr(self._zone),
repr(self._key),
)
def unwrap_shim(self):
"""Returns the underlying class that the shim is a wrapper for.
This is a shim-specific method equivalent to
:func:`pytz_deprecation_shim.helpers.upgrade_tzinfo`. It is provided as
a method to allow end-users to upgrade shim timezones without requiring
an explicit dependency on ``pytz_deprecation_shim``, e.g.:
.. code-block:: python
if getattr(tz, "unwrap_shim", None) is None:
tz = tz.unwrap_shim()
"""
return self._zone
@property
def zone(self):
warnings.warn(
"The zone attribute is specific to pytz's interface; "
+ "please migrate to a new time zone provider. "
+ "For more details on how to do so, see %s"
% PYTZ_MIGRATION_GUIDE_URL,
PytzUsageWarning,
stacklevel=2,
)
return self._key
def localize(self, dt, is_dst=IS_DST_SENTINEL):
warnings.warn(
"The localize method is no longer necessary, as this "
+ "time zone supports the fold attribute (PEP 495). "
+ "For more details on migrating to a PEP 495-compliant "
+ "implementation, see %s" % PYTZ_MIGRATION_GUIDE_URL,
PytzUsageWarning,
stacklevel=2,
)
if dt.tzinfo is not None:
raise ValueError("Not naive datetime (tzinfo is already set)")
dt_out = dt.replace(tzinfo=self)
if is_dst is IS_DST_SENTINEL:
return dt_out
dt_ambiguous = _compat.is_ambiguous(dt_out)
dt_imaginary = (
_compat.is_imaginary(dt_out) if not dt_ambiguous else False
)
if is_dst is None:
if dt_imaginary:
raise get_exception(
NonExistentTimeError, dt.replace(tzinfo=None)
)
if dt_ambiguous:
raise get_exception(AmbiguousTimeError, dt.replace(tzinfo=None))
elif dt_ambiguous or dt_imaginary:
# Start by normalizing the folds; dt_out may have fold=0 or fold=1,
# but we need to know the DST offset on both sides anyway, so we
# will get one datetime representing each side of the fold, then
# decide which one we're going to return.
if _compat.get_fold(dt_out):
dt_enfolded = dt_out
dt_out = _compat.enfold(dt_out, fold=0)
else:
dt_enfolded = _compat.enfold(dt_out, fold=1)
# Now we want to decide whether the fold=0 or fold=1 represents
# what pytz would return for `is_dst=True`
enfolded_dst = bool(dt_enfolded.dst())
if bool(dt_out.dst()) == enfolded_dst:
# If this is not a transition between standard time and
# daylight saving time, pytz will consider the larger offset
# the DST offset.
enfolded_dst = dt_enfolded.utcoffset() > dt_out.utcoffset()
# The default we've established is that dt_out is fold=0; swap it
# for the fold=1 datetime if is_dst == True and the enfolded side
# is DST or if is_dst == False and the enfolded side is *not* DST.
if is_dst == enfolded_dst:
dt_out = dt_enfolded
return dt_out
def normalize(self, dt):
warnings.warn(
"The normalize method is no longer necessary, as this "
+ "time zone supports the fold attribute (PEP 495). "
+ "For more details on migrating to a PEP 495-compliant "
+ "implementation, see %s" % PYTZ_MIGRATION_GUIDE_URL,
PytzUsageWarning,
stacklevel=2,
)
if dt.tzinfo is None:
raise ValueError("Naive time - no tzinfo set")
if dt.tzinfo is self:
return dt
return dt.astimezone(self)
def __copy__(self):
return self
def __deepcopy__(self, memo=None):
return self
def __reduce__(self):
return wrap_zone, (self._zone, self._key)
UTC = wrap_zone(_compat.UTC, "UTC")
PYTZ_MIGRATION_GUIDE_URL = (
"https://pytz-deprecation-shim.readthedocs.io/en/latest/migration.html"
)

View file

@ -1,90 +0,0 @@
"""
This module contains helper functions to ease the transition from ``pytz`` to
another :pep:`495`-compatible library.
"""
from . import _common, _compat
from ._impl import _PytzShimTimezone
_PYTZ_BASE_CLASSES = None
def is_pytz_zone(tz):
"""Check if a time zone is a ``pytz`` time zone.
This will only import ``pytz`` if it has already been imported, and does
not rely on the existence of the ``localize`` or ``normalize`` methods
(since the shim classes also have these methods, but are not ``pytz``
zones).
"""
# If pytz is not in sys.modules, then we will assume the time zone is not a
# pytz zone. It is possible that someone has manipulated sys.modules to
# remove pytz, but that's the kind of thing that causes all kinds of other
# problems anyway, so we'll call that an unsupported configuration.
if not _common.pytz_imported():
return False
if _PYTZ_BASE_CLASSES is None:
_populate_pytz_base_classes()
return isinstance(tz, _PYTZ_BASE_CLASSES)
def upgrade_tzinfo(tz):
"""Convert a ``pytz`` or shim timezone into its modern equivalent.
The shim classes are thin wrappers around :mod:`zoneinfo` or
:mod:`dateutil.tz` implementations of the :class:`datetime.tzinfo` base
class. This function removes the shim and returns the underlying "upgraded"
time zone.
When passed a ``pytz`` zone (not a shim), this returns the non-``pytz``
equivalent. This may fail if ``pytz`` is using a data source incompatible
with the upgraded provider's data source, or if the ``pytz`` zone was built
from a file rather than an IANA key.
When passed an object that is not a shim or a ``pytz`` zone, this returns
the original object.
:param tz:
A :class:`datetime.tzinfo` object.
:raises KeyError:
If a ``pytz`` zone is passed to the function with no equivalent in the
:pep:`495`-compatible library's version of the Olson database.
:return:
A :pep:`495`-compatible equivalent of any ``pytz`` or shim
class, or the original object.
"""
if isinstance(tz, _PytzShimTimezone):
return tz._zone
if is_pytz_zone(tz):
if tz.zone is None:
# This is a fixed offset zone
offset = tz.utcoffset(None)
offset_minutes = offset.total_seconds() / 60
return _compat.get_fixed_offset_zone(offset_minutes)
if tz.zone == "UTC":
return _compat.UTC
return _compat.get_timezone(tz.zone)
return tz
def _populate_pytz_base_classes():
import pytz
from pytz.tzinfo import BaseTzInfo
base_classes = (BaseTzInfo, pytz._FixedOffset)
# In releases prior to 2018.4, pytz.UTC was not a subclass of BaseTzInfo
if not isinstance(pytz.UTC, BaseTzInfo): # pragma: nocover
base_classes = base_classes + (type(pytz.UTC),)
global _PYTZ_BASE_CLASSES
_PYTZ_BASE_CLASSES = base_classes

View file

@ -1,6 +1,6 @@
# IANA versions like 2020a are not valid PEP 440 identifiers; the recommended # IANA versions like 2020a are not valid PEP 440 identifiers; the recommended
# way to translate the version is to use YYYY.n where `n` is a 0-based index. # way to translate the version is to use YYYY.n where `n` is a 0-based index.
__version__ = "2021.5" __version__ = "2021.2.post0"
# This exposes the original IANA version number. # This exposes the original IANA version number.
IANA_VERSION = "2021e" IANA_VERSION = "2021b"

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,4 +1,4 @@
# version 2021e # version 2021b
# This zic input file is in the public domain. # This zic input file is in the public domain.
R d 1916 o - Jun 14 23s 1 S R d 1916 o - Jun 14 23s 1 S
R d 1916 1919 - O Su>=1 23s 0 - R d 1916 1919 - O Su>=1 23s 0 -
@ -43,16 +43,6 @@ Z Africa/Ndjamena 1:0:12 - LMT 1912
1 - WAT 1 - WAT
Z Africa/Abidjan -0:16:8 - LMT 1912 Z Africa/Abidjan -0:16:8 - LMT 1912
0 - GMT 0 - GMT
L Africa/Abidjan Africa/Accra
L Africa/Abidjan Africa/Bamako
L Africa/Abidjan Africa/Banjul
L Africa/Abidjan Africa/Conakry
L Africa/Abidjan Africa/Dakar
L Africa/Abidjan Africa/Freetown
L Africa/Abidjan Africa/Lome
L Africa/Abidjan Africa/Nouakchott
L Africa/Abidjan Africa/Ouagadougou
L Africa/Abidjan Atlantic/St_Helena
R K 1940 o - Jul 15 0 1 S R K 1940 o - Jul 15 0 1 S
R K 1940 o - O 1 0 0 - R K 1940 o - O 1 0 0 -
R K 1941 o - Ap 15 0 1 S R K 1941 o - Ap 15 0 1 S
@ -96,15 +86,6 @@ Z Africa/Nairobi 2:27:16 - LMT 1908 May
2:30 - +0230 1936 D 31 24 2:30 - +0230 1936 D 31 24
2:45 - +0245 1942 Jul 31 24 2:45 - +0245 1942 Jul 31 24
3 - EAT 3 - EAT
L Africa/Nairobi Africa/Addis_Ababa
L Africa/Nairobi Africa/Asmara
L Africa/Nairobi Africa/Dar_es_Salaam
L Africa/Nairobi Africa/Djibouti
L Africa/Nairobi Africa/Kampala
L Africa/Nairobi Africa/Mogadishu
L Africa/Nairobi Indian/Antananarivo
L Africa/Nairobi Indian/Comoro
L Africa/Nairobi Indian/Mayotte
Z Africa/Monrovia -0:43:8 - LMT 1882 Z Africa/Monrovia -0:43:8 - LMT 1882
-0:43:8 - MMT 1919 Mar -0:43:8 - MMT 1919 Mar
-0:44:30 - MMT 1972 Ja 7 -0:44:30 - MMT 1972 Ja 7
@ -335,13 +316,6 @@ Z Africa/El_Aaiun -0:52:48 - LMT 1934
1 M +01/+00 1 M +01/+00
Z Africa/Maputo 2:10:20 - LMT 1903 Mar Z Africa/Maputo 2:10:20 - LMT 1903 Mar
2 - CAT 2 - CAT
L Africa/Maputo Africa/Blantyre
L Africa/Maputo Africa/Bujumbura
L Africa/Maputo Africa/Gaborone
L Africa/Maputo Africa/Harare
L Africa/Maputo Africa/Kigali
L Africa/Maputo Africa/Lubumbashi
L Africa/Maputo Africa/Lusaka
R NA 1994 o - Mar 21 0 -1 WAT R NA 1994 o - Mar 21 0 -1 WAT
R NA 1994 2017 - S Su>=1 2 0 CAT R NA 1994 2017 - S Su>=1 2 0 CAT
R NA 1995 2017 - Ap Su>=1 2 -1 WAT R NA 1995 2017 - Ap Su>=1 2 -1 WAT
@ -356,15 +330,6 @@ Z Africa/Lagos 0:13:35 - LMT 1905 Jul
0:13:35 - LMT 1914 0:13:35 - LMT 1914
0:30 - +0030 1919 S 0:30 - +0030 1919 S
1 - WAT 1 - WAT
L Africa/Lagos Africa/Bangui
L Africa/Lagos Africa/Brazzaville
L Africa/Lagos Africa/Douala
L Africa/Lagos Africa/Kinshasa
L Africa/Lagos Africa/Libreville
L Africa/Lagos Africa/Luanda
L Africa/Lagos Africa/Malabo
L Africa/Lagos Africa/Niamey
L Africa/Lagos Africa/Porto-Novo
Z Indian/Reunion 3:41:52 - LMT 1911 Jun Z Indian/Reunion 3:41:52 - LMT 1911 Jun
4 - +04 4 - +04
Z Africa/Sao_Tome 0:26:56 - LMT 1884 Z Africa/Sao_Tome 0:26:56 - LMT 1884
@ -379,8 +344,6 @@ R SA 1943 1944 - Mar Su>=15 2 0 -
Z Africa/Johannesburg 1:52 - LMT 1892 F 8 Z Africa/Johannesburg 1:52 - LMT 1892 F 8
1:30 - SAST 1903 Mar 1:30 - SAST 1903 Mar
2 SA SAST 2 SA SAST
L Africa/Johannesburg Africa/Maseru
L Africa/Johannesburg Africa/Mbabane
R SD 1970 o - May 1 0 1 S R SD 1970 o - May 1 0 1 S
R SD 1970 1985 - O 15 0 0 - R SD 1970 1985 - O 15 0 0 -
R SD 1971 o - Ap 30 0 1 S R SD 1971 o - Ap 30 0 1 S
@ -608,7 +571,6 @@ Z Asia/Famagusta 2:15:48 - LMT 1921 N 14
2 E EE%sT 2016 S 8 2 E EE%sT 2016 S 8
3 - +03 2017 O 29 1u 3 - +03 2017 O 29 1u
2 E EE%sT 2 E EE%sT
L Asia/Nicosia Europe/Nicosia
Z Asia/Tbilisi 2:59:11 - LMT 1880 Z Asia/Tbilisi 2:59:11 - LMT 1880
2:59:11 - TBMT 1924 May 2 2:59:11 - TBMT 1924 May 2
3 - +03 1957 Mar 3 - +03 1957 Mar
@ -1112,8 +1074,7 @@ R P 2016 2018 - O Sa>=24 1 0 -
R P 2019 o - Mar 29 0 1 S R P 2019 o - Mar 29 0 1 S
R P 2019 o - O Sa>=24 0 0 - R P 2019 o - O Sa>=24 0 0 -
R P 2020 ma - Mar Sa>=24 0 1 S R P 2020 ma - Mar Sa>=24 0 1 S
R P 2020 o - O 24 1 0 - R P 2020 ma - O Sa>=24 1 0 -
R P 2021 ma - O lastF 1 0 -
Z Asia/Gaza 2:17:52 - LMT 1900 O Z Asia/Gaza 2:17:52 - LMT 1900 O
2 Z EET/EEST 1948 May 15 2 Z EET/EEST 1948 May 15
2 K EE%sT 1967 Jun 5 2 K EE%sT 1967 Jun 5
@ -1146,12 +1107,8 @@ Z Asia/Manila -15:56 - LMT 1844 D 31
Z Asia/Qatar 3:26:8 - LMT 1920 Z Asia/Qatar 3:26:8 - LMT 1920
4 - +04 1972 Jun 4 - +04 1972 Jun
3 - +03 3 - +03
L Asia/Qatar Asia/Bahrain
Z Asia/Riyadh 3:6:52 - LMT 1947 Mar 14 Z Asia/Riyadh 3:6:52 - LMT 1947 Mar 14
3 - +03 3 - +03
L Asia/Riyadh Antarctica/Syowa
L Asia/Riyadh Asia/Aden
L Asia/Riyadh Asia/Kuwait
Z Asia/Singapore 6:55:25 - LMT 1901 Z Asia/Singapore 6:55:25 - LMT 1901
6:55:25 - SMT 1905 Jun 6:55:25 - SMT 1905 Jun
7 - +07 1933 7 - +07 1933
@ -1221,8 +1178,6 @@ Z Asia/Dushanbe 4:35:12 - LMT 1924 May 2
Z Asia/Bangkok 6:42:4 - LMT 1880 Z Asia/Bangkok 6:42:4 - LMT 1880
6:42:4 - BMT 1920 Ap 6:42:4 - BMT 1920 Ap
7 - +07 7 - +07
L Asia/Bangkok Asia/Phnom_Penh
L Asia/Bangkok Asia/Vientiane
Z Asia/Ashgabat 3:53:32 - LMT 1924 May 2 Z Asia/Ashgabat 3:53:32 - LMT 1924 May 2
4 - +04 1930 Jun 21 4 - +04 1930 Jun 21
5 R +05/+06 1991 Mar 31 2 5 R +05/+06 1991 Mar 31 2
@ -1230,7 +1185,6 @@ Z Asia/Ashgabat 3:53:32 - LMT 1924 May 2
5 - +05 5 - +05
Z Asia/Dubai 3:41:12 - LMT 1920 Z Asia/Dubai 3:41:12 - LMT 1920
4 - +04 4 - +04
L Asia/Dubai Asia/Muscat
Z Asia/Samarkand 4:27:53 - LMT 1924 May 2 Z Asia/Samarkand 4:27:53 - LMT 1924 May 2
4 - +04 1930 Jun 21 4 - +04 1930 Jun 21
5 - +05 1981 Ap 5 - +05 1981 Ap
@ -1419,11 +1373,10 @@ R FJ 2011 o - Mar Su>=1 3 0 -
R FJ 2012 2013 - Ja Su>=18 3 0 - R FJ 2012 2013 - Ja Su>=18 3 0 -
R FJ 2014 o - Ja Su>=18 2 0 - R FJ 2014 o - Ja Su>=18 2 0 -
R FJ 2014 2018 - N Su>=1 2 1 - R FJ 2014 2018 - N Su>=1 2 1 -
R FJ 2015 2021 - Ja Su>=12 3 0 - R FJ 2015 ma - Ja Su>=12 3 0 -
R FJ 2019 o - N Su>=8 2 1 - R FJ 2019 o - N Su>=8 2 1 -
R FJ 2020 o - D 20 2 1 - R FJ 2020 o - D 20 2 1 -
R FJ 2022 ma - N Su>=8 2 1 - R FJ 2021 ma - N Su>=8 2 1 -
R FJ 2023 ma - Ja Su>=12 3 0 -
Z Pacific/Fiji 11:55:44 - LMT 1915 O 26 Z Pacific/Fiji 11:55:44 - LMT 1915 O 26
12 FJ +12/+13 12 FJ +12/+13
Z Pacific/Gambier -8:59:48 - LMT 1912 O Z Pacific/Gambier -8:59:48 - LMT 1912 O
@ -1452,7 +1405,6 @@ Z Pacific/Guam -14:21 - LMT 1844 D 31
9 - +09 1944 Jul 31 9 - +09 1944 Jul 31
10 Gu G%sT 2000 D 23 10 Gu G%sT 2000 D 23
10 - ChST 10 - ChST
L Pacific/Guam Pacific/Saipan
Z Pacific/Tarawa 11:32:4 - LMT 1901 Z Pacific/Tarawa 11:32:4 - LMT 1901
12 - +12 12 - +12
Z Pacific/Kanton 0 - -00 1937 Au 31 Z Pacific/Kanton 0 - -00 1937 Au 31
@ -1545,7 +1497,6 @@ Z Pacific/Auckland 11:39:4 - LMT 1868 N 2
Z Pacific/Chatham 12:13:48 - LMT 1868 N 2 Z Pacific/Chatham 12:13:48 - LMT 1868 N 2
12:15 - +1215 1946 12:15 - +1215 1946
12:45 k +1245/+1345 12:45 k +1245/+1345
L Pacific/Auckland Antarctica/McMurdo
R CK 1978 o - N 12 0 0:30 - R CK 1978 o - N 12 0 0:30 -
R CK 1979 1991 - Mar Su>=1 0 0 - R CK 1979 1991 - Mar Su>=1 0 0 -
R CK 1979 1990 - O lastSu 0 0:30 - R CK 1979 1990 - O lastSu 0 0:30 -
@ -1569,7 +1520,6 @@ Z Pacific/Palau -15:2:4 - LMT 1844 D 31
Z Pacific/Port_Moresby 9:48:40 - LMT 1880 Z Pacific/Port_Moresby 9:48:40 - LMT 1880
9:48:32 - PMMT 1895 9:48:32 - PMMT 1895
10 - +10 10 - +10
L Pacific/Port_Moresby Antarctica/DumontDUrville
Z Pacific/Bougainville 10:22:16 - LMT 1880 Z Pacific/Bougainville 10:22:16 - LMT 1880
9:48:32 - PMMT 1895 9:48:32 - PMMT 1895
10 - +10 1942 Jul 10 - +10 1942 Jul
@ -1582,7 +1532,6 @@ Z Pacific/Pitcairn -8:40:20 - LMT 1901
Z Pacific/Pago_Pago 12:37:12 - LMT 1892 Jul 5 Z Pacific/Pago_Pago 12:37:12 - LMT 1892 Jul 5
-11:22:48 - LMT 1911 -11:22:48 - LMT 1911
-11 - SST -11 - SST
L Pacific/Pago_Pago Pacific/Midway
R WS 2010 o - S lastSu 0 1 - R WS 2010 o - S lastSu 0 1 -
R WS 2011 o - Ap Sa>=1 4 0 - R WS 2011 o - Ap Sa>=1 4 0 -
R WS 2011 o - S lastSa 3 1 - R WS 2011 o - S lastSa 3 1 -
@ -1692,9 +1641,6 @@ Z Europe/London -0:1:15 - LMT 1847 D 1 0s
1 - BST 1971 O 31 2u 1 - BST 1971 O 31 2u
0 G %s 1996 0 G %s 1996
0 E GMT/BST 0 E GMT/BST
L Europe/London Europe/Jersey
L Europe/London Europe/Guernsey
L Europe/London Europe/Isle_of_Man
R IE 1971 o - O 31 2u -1 - R IE 1971 o - O 31 2u -1 -
R IE 1972 1980 - Mar Su>=16 2u 0 - R IE 1972 1980 - Mar Su>=16 2u 0 -
R IE 1972 1980 - O Su>=23 2u -1 - R IE 1972 1980 - O Su>=23 2u -1 -
@ -1958,7 +1904,6 @@ Z Europe/Helsinki 1:39:49 - LMT 1878 May 31
1:39:49 - HMT 1921 May 1:39:49 - HMT 1921 May
2 FI EE%sT 1983 2 FI EE%sT 1983
2 E EE%sT 2 E EE%sT
L Europe/Helsinki Europe/Mariehamn
R F 1916 o - Jun 14 23s 1 S R F 1916 o - Jun 14 23s 1 S
R F 1916 1919 - O Su>=1 23s 0 - R F 1916 1919 - O Su>=1 23s 0 -
R F 1917 o - Mar 24 23s 1 S R F 1917 o - Mar 24 23s 1 S
@ -2024,7 +1969,6 @@ Z Europe/Berlin 0:53:28 - LMT 1893 Ap
1 So CE%sT 1946 1 So CE%sT 1946
1 DE CE%sT 1980 1 DE CE%sT 1980
1 E CE%sT 1 E CE%sT
L Europe/Zurich Europe/Busingen
Z Europe/Gibraltar -0:21:24 - LMT 1880 Au 2 0s Z Europe/Gibraltar -0:21:24 - LMT 1880 Au 2 0s
0 G %s 1957 Ap 14 2 0 G %s 1957 Ap 14 2
1 - CET 1982 1 - CET 1982
@ -2145,8 +2089,6 @@ Z Europe/Rome 0:49:56 - LMT 1866 D 12
1 c CE%sT 1944 Jun 4 1 c CE%sT 1944 Jun 4
1 I CE%sT 1980 1 I CE%sT 1980
1 E CE%sT 1 E CE%sT
L Europe/Rome Europe/Vatican
L Europe/Rome Europe/San_Marino
R LV 1989 1996 - Mar lastSu 2s 1 S R LV 1989 1996 - Mar lastSu 2s 1 S
R LV 1989 1996 - S lastSu 2s 0 - R LV 1989 1996 - S lastSu 2s 0 -
Z Europe/Riga 1:36:34 - LMT 1880 Z Europe/Riga 1:36:34 - LMT 1880
@ -2164,7 +2106,6 @@ Z Europe/Riga 1:36:34 - LMT 1880
2 E EE%sT 2000 F 29 2 E EE%sT 2000 F 29
2 - EET 2001 Ja 2 2 - EET 2001 Ja 2
2 E EE%sT 2 E EE%sT
L Europe/Zurich Europe/Vaduz
Z Europe/Vilnius 1:41:16 - LMT 1880 Z Europe/Vilnius 1:41:16 - LMT 1880
1:24 - WMT 1917 1:24 - WMT 1917
1:35:36 - KMT 1919 O 10 1:35:36 - KMT 1919 O 10
@ -2276,7 +2217,6 @@ Z Europe/Oslo 0:43 - LMT 1895
1 c CE%sT 1945 Ap 2 2 1 c CE%sT 1945 Ap 2 2
1 NO CE%sT 1980 1 NO CE%sT 1980
1 E CE%sT 1 E CE%sT
L Europe/Oslo Arctic/Longyearbyen
R O 1918 1919 - S 16 2s 0 - R O 1918 1919 - S 16 2s 0 -
R O 1919 o - Ap 15 2s 1 S R O 1919 o - Ap 15 2s 1 S
R O 1944 o - Ap 3 2s 1 S R O 1944 o - Ap 3 2s 1 S
@ -2646,12 +2586,6 @@ Z Europe/Belgrade 1:22 - LMT 1884
1 1 CEST 1945 S 16 2s 1 1 CEST 1945 S 16 2s
1 - CET 1982 N 27 1 - CET 1982 N 27
1 E CE%sT 1 E CE%sT
L Europe/Belgrade Europe/Ljubljana
L Europe/Belgrade Europe/Podgorica
L Europe/Belgrade Europe/Sarajevo
L Europe/Belgrade Europe/Skopje
L Europe/Belgrade Europe/Zagreb
L Europe/Prague Europe/Bratislava
R s 1918 o - Ap 15 23 1 S R s 1918 o - Ap 15 23 1 S
R s 1918 1919 - O 6 24s 0 - R s 1918 1919 - O 6 24s 0 -
R s 1919 o - Ap 6 23 1 S R s 1919 o - Ap 6 23 1 S
@ -2779,7 +2713,6 @@ Z Europe/Istanbul 1:55:52 - LMT 1880
2 1 EEST 2015 N 8 1u 2 1 EEST 2015 N 8 1u
2 E EE%sT 2016 S 7 2 E EE%sT 2016 S 7
3 - +03 3 - +03
L Europe/Istanbul Asia/Istanbul
Z Europe/Kiev 2:2:4 - LMT 1880 Z Europe/Kiev 2:2:4 - LMT 1880
2:2:4 - KMT 1924 May 2 2:2:4 - KMT 1924 May 2
2 - EET 1930 Jun 21 2 - EET 1930 Jun 21
@ -2955,7 +2888,6 @@ Z America/Phoenix -7:28:18 - LMT 1883 N 18 11:31:42
-7 - MST 1967 -7 - MST 1967
-7 u M%sT 1968 Mar 21 -7 u M%sT 1968 Mar 21
-7 - MST -7 - MST
L America/Phoenix America/Creston
Z America/Boise -7:44:49 - LMT 1883 N 18 12:15:11 Z America/Boise -7:44:49 - LMT 1883 N 18 12:15:11
-8 u P%sT 1923 May 13 2 -8 u P%sT 1923 May 13 2
-7 u M%sT 1974 -7 u M%sT 1974
@ -3254,7 +3186,6 @@ Z America/Toronto -5:17:32 - LMT 1895
-5 C E%sT 1946 -5 C E%sT 1946
-5 t E%sT 1974 -5 t E%sT 1974
-5 C E%sT -5 C E%sT
L America/Toronto America/Nassau
Z America/Thunder_Bay -5:57 - LMT 1895 Z America/Thunder_Bay -5:57 - LMT 1895
-6 - CST 1910 -6 - CST 1910
-5 - EST 1942 -5 - EST 1942
@ -3705,31 +3636,10 @@ Z America/Managua -5:45:8 - LMT 1890
Z America/Panama -5:18:8 - LMT 1890 Z America/Panama -5:18:8 - LMT 1890
-5:19:36 - CMT 1908 Ap 22 -5:19:36 - CMT 1908 Ap 22
-5 - EST -5 - EST
L America/Panama America/Atikokan
L America/Panama America/Cayman
Z America/Puerto_Rico -4:24:25 - LMT 1899 Mar 28 12 Z America/Puerto_Rico -4:24:25 - LMT 1899 Mar 28 12
-4 - AST 1942 May 3 -4 - AST 1942 May 3
-4 u A%sT 1946 -4 u A%sT 1946
-4 - AST -4 - AST
L America/Puerto_Rico America/Anguilla
L America/Puerto_Rico America/Antigua
L America/Puerto_Rico America/Aruba
L America/Puerto_Rico America/Curacao
L America/Puerto_Rico America/Blanc-Sablon
L America/Puerto_Rico America/Dominica
L America/Puerto_Rico America/Grenada
L America/Puerto_Rico America/Guadeloupe
L America/Puerto_Rico America/Kralendijk
L America/Puerto_Rico America/Lower_Princes
L America/Puerto_Rico America/Marigot
L America/Puerto_Rico America/Montserrat
L America/Puerto_Rico America/Port_of_Spain
L America/Puerto_Rico America/St_Barthelemy
L America/Puerto_Rico America/St_Kitts
L America/Puerto_Rico America/St_Lucia
L America/Puerto_Rico America/St_Thomas
L America/Puerto_Rico America/St_Vincent
L America/Puerto_Rico America/Tortola
Z America/Miquelon -3:44:40 - LMT 1911 May 15 Z America/Miquelon -3:44:40 - LMT 1911 May 15
-4 - AST 1980 May -4 - AST 1980 May
-3 - -03 1987 -3 - -03 1987
@ -4311,46 +4221,114 @@ Z Etc/GMT+10 -10 - -10
Z Etc/GMT+11 -11 - -11 Z Etc/GMT+11 -11 - -11
Z Etc/GMT+12 -12 - -12 Z Etc/GMT+12 -12 - -12
Z Factory 0 - -00 Z Factory 0 - -00
L Africa/Abidjan Africa/Accra
L Africa/Nairobi Africa/Addis_Ababa
L Africa/Nairobi Africa/Asmara
L Africa/Nairobi Africa/Asmera L Africa/Nairobi Africa/Asmera
L Africa/Abidjan Africa/Bamako
L Africa/Lagos Africa/Bangui
L Africa/Abidjan Africa/Banjul
L Africa/Maputo Africa/Blantyre
L Africa/Lagos Africa/Brazzaville
L Africa/Maputo Africa/Bujumbura
L Africa/Abidjan Africa/Conakry
L Africa/Abidjan Africa/Dakar
L Africa/Nairobi Africa/Dar_es_Salaam
L Africa/Nairobi Africa/Djibouti
L Africa/Lagos Africa/Douala
L Africa/Abidjan Africa/Freetown
L Africa/Maputo Africa/Gaborone
L Africa/Maputo Africa/Harare
L Africa/Nairobi Africa/Kampala
L Africa/Maputo Africa/Kigali
L Africa/Lagos Africa/Kinshasa
L Africa/Lagos Africa/Libreville
L Africa/Abidjan Africa/Lome
L Africa/Lagos Africa/Luanda
L Africa/Maputo Africa/Lubumbashi
L Africa/Maputo Africa/Lusaka
L Africa/Lagos Africa/Malabo
L Africa/Johannesburg Africa/Maseru
L Africa/Johannesburg Africa/Mbabane
L Africa/Nairobi Africa/Mogadishu
L Africa/Lagos Africa/Niamey
L Africa/Abidjan Africa/Nouakchott
L Africa/Abidjan Africa/Ouagadougou
L Africa/Lagos Africa/Porto-Novo
L Africa/Abidjan Africa/Timbuktu L Africa/Abidjan Africa/Timbuktu
L America/Puerto_Rico America/Anguilla
L America/Puerto_Rico America/Antigua
L America/Argentina/Catamarca America/Argentina/ComodRivadavia L America/Argentina/Catamarca America/Argentina/ComodRivadavia
L America/Puerto_Rico America/Aruba
L America/Panama America/Atikokan
L America/Adak America/Atka L America/Adak America/Atka
L America/Puerto_Rico America/Blanc-Sablon
L America/Argentina/Buenos_Aires America/Buenos_Aires L America/Argentina/Buenos_Aires America/Buenos_Aires
L America/Argentina/Catamarca America/Catamarca L America/Argentina/Catamarca America/Catamarca
L America/Panama America/Cayman
L America/Panama America/Coral_Harbour L America/Panama America/Coral_Harbour
L America/Argentina/Cordoba America/Cordoba L America/Argentina/Cordoba America/Cordoba
L America/Phoenix America/Creston
L America/Puerto_Rico America/Curacao
L America/Puerto_Rico America/Dominica
L America/Tijuana America/Ensenada L America/Tijuana America/Ensenada
L America/Indiana/Indianapolis America/Fort_Wayne L America/Indiana/Indianapolis America/Fort_Wayne
L America/Nuuk America/Godthab L America/Nuuk America/Godthab
L America/Puerto_Rico America/Grenada
L America/Puerto_Rico America/Guadeloupe
L America/Indiana/Indianapolis America/Indianapolis L America/Indiana/Indianapolis America/Indianapolis
L America/Argentina/Jujuy America/Jujuy L America/Argentina/Jujuy America/Jujuy
L America/Indiana/Knox America/Knox_IN L America/Indiana/Knox America/Knox_IN
L America/Puerto_Rico America/Kralendijk
L America/Kentucky/Louisville America/Louisville L America/Kentucky/Louisville America/Louisville
L America/Puerto_Rico America/Lower_Princes
L America/Puerto_Rico America/Marigot
L America/Argentina/Mendoza America/Mendoza L America/Argentina/Mendoza America/Mendoza
L America/Toronto America/Montreal L America/Toronto America/Montreal
L America/Puerto_Rico America/Montserrat
L America/Toronto America/Nassau
L America/Puerto_Rico America/Port_of_Spain
L America/Rio_Branco America/Porto_Acre L America/Rio_Branco America/Porto_Acre
L America/Argentina/Cordoba America/Rosario L America/Argentina/Cordoba America/Rosario
L America/Tijuana America/Santa_Isabel L America/Tijuana America/Santa_Isabel
L America/Denver America/Shiprock L America/Denver America/Shiprock
L America/Puerto_Rico America/St_Barthelemy
L America/Puerto_Rico America/St_Kitts
L America/Puerto_Rico America/St_Lucia
L America/Puerto_Rico America/St_Thomas
L America/Puerto_Rico America/St_Vincent
L America/Puerto_Rico America/Tortola
L America/Puerto_Rico America/Virgin L America/Puerto_Rico America/Virgin
L Pacific/Port_Moresby Antarctica/DumontDUrville
L Pacific/Auckland Antarctica/McMurdo
L Pacific/Auckland Antarctica/South_Pole L Pacific/Auckland Antarctica/South_Pole
L Asia/Riyadh Antarctica/Syowa
L Europe/Oslo Arctic/Longyearbyen
L Asia/Riyadh Asia/Aden
L Asia/Ashgabat Asia/Ashkhabad L Asia/Ashgabat Asia/Ashkhabad
L Asia/Qatar Asia/Bahrain
L Asia/Kolkata Asia/Calcutta L Asia/Kolkata Asia/Calcutta
L Asia/Shanghai Asia/Chongqing L Asia/Shanghai Asia/Chongqing
L Asia/Shanghai Asia/Chungking L Asia/Shanghai Asia/Chungking
L Asia/Dhaka Asia/Dacca L Asia/Dhaka Asia/Dacca
L Asia/Shanghai Asia/Harbin L Asia/Shanghai Asia/Harbin
L Europe/Istanbul Asia/Istanbul
L Asia/Urumqi Asia/Kashgar L Asia/Urumqi Asia/Kashgar
L Asia/Kathmandu Asia/Katmandu L Asia/Kathmandu Asia/Katmandu
L Asia/Riyadh Asia/Kuwait
L Asia/Macau Asia/Macao L Asia/Macau Asia/Macao
L Asia/Dubai Asia/Muscat
L Asia/Bangkok Asia/Phnom_Penh
L Asia/Yangon Asia/Rangoon L Asia/Yangon Asia/Rangoon
L Asia/Ho_Chi_Minh Asia/Saigon L Asia/Ho_Chi_Minh Asia/Saigon
L Asia/Jerusalem Asia/Tel_Aviv L Asia/Jerusalem Asia/Tel_Aviv
L Asia/Thimphu Asia/Thimbu L Asia/Thimphu Asia/Thimbu
L Asia/Makassar Asia/Ujung_Pandang L Asia/Makassar Asia/Ujung_Pandang
L Asia/Ulaanbaatar Asia/Ulan_Bator L Asia/Ulaanbaatar Asia/Ulan_Bator
L Asia/Bangkok Asia/Vientiane
L Atlantic/Faroe Atlantic/Faeroe L Atlantic/Faroe Atlantic/Faeroe
L Europe/Oslo Atlantic/Jan_Mayen L Europe/Berlin Atlantic/Jan_Mayen
L Africa/Abidjan Atlantic/St_Helena
L Australia/Sydney Australia/ACT L Australia/Sydney Australia/ACT
L Australia/Sydney Australia/Canberra L Australia/Sydney Australia/Canberra
L Australia/Hobart Australia/Currie L Australia/Hobart Australia/Currie
@ -4382,7 +4360,22 @@ L Africa/Cairo Egypt
L Europe/Dublin Eire L Europe/Dublin Eire
L Etc/UTC Etc/UCT L Etc/UTC Etc/UCT
L Europe/London Europe/Belfast L Europe/London Europe/Belfast
L Europe/Prague Europe/Bratislava
L Europe/Zurich Europe/Busingen
L Europe/London Europe/Guernsey
L Europe/London Europe/Isle_of_Man
L Europe/London Europe/Jersey
L Europe/Belgrade Europe/Ljubljana
L Europe/Helsinki Europe/Mariehamn
L Asia/Nicosia Europe/Nicosia
L Europe/Belgrade Europe/Podgorica
L Europe/Rome Europe/San_Marino
L Europe/Belgrade Europe/Sarajevo
L Europe/Belgrade Europe/Skopje
L Europe/Chisinau Europe/Tiraspol L Europe/Chisinau Europe/Tiraspol
L Europe/Zurich Europe/Vaduz
L Europe/Rome Europe/Vatican
L Europe/Belgrade Europe/Zagreb
L Europe/London GB L Europe/London GB
L Europe/London GB-Eire L Europe/London GB-Eire
L Etc/GMT GMT+0 L Etc/GMT GMT+0
@ -4391,6 +4384,9 @@ L Etc/GMT GMT0
L Etc/GMT Greenwich L Etc/GMT Greenwich
L Asia/Hong_Kong Hongkong L Asia/Hong_Kong Hongkong
L Atlantic/Reykjavik Iceland L Atlantic/Reykjavik Iceland
L Africa/Nairobi Indian/Antananarivo
L Africa/Nairobi Indian/Comoro
L Africa/Nairobi Indian/Mayotte
L Asia/Tehran Iran L Asia/Tehran Iran
L Asia/Jerusalem Israel L Asia/Jerusalem Israel
L America/Jamaica Jamaica L America/Jamaica Jamaica
@ -4406,7 +4402,9 @@ L America/Denver Navajo
L Asia/Shanghai PRC L Asia/Shanghai PRC
L Pacific/Kanton Pacific/Enderbury L Pacific/Kanton Pacific/Enderbury
L Pacific/Honolulu Pacific/Johnston L Pacific/Honolulu Pacific/Johnston
L Pacific/Pago_Pago Pacific/Midway
L Pacific/Pohnpei Pacific/Ponape L Pacific/Pohnpei Pacific/Ponape
L Pacific/Guam Pacific/Saipan
L Pacific/Pago_Pago Pacific/Samoa L Pacific/Pago_Pago Pacific/Samoa
L Pacific/Chuuk Pacific/Truk L Pacific/Chuuk Pacific/Truk
L Pacific/Chuuk Pacific/Yap L Pacific/Chuuk Pacific/Yap

View file

@ -2,58 +2,21 @@ Africa/Algiers
Atlantic/Cape_Verde Atlantic/Cape_Verde
Africa/Ndjamena Africa/Ndjamena
Africa/Abidjan Africa/Abidjan
Africa/Accra
Africa/Bamako
Africa/Banjul
Africa/Conakry
Africa/Dakar
Africa/Freetown
Africa/Lome
Africa/Nouakchott
Africa/Ouagadougou
Atlantic/St_Helena
Africa/Cairo Africa/Cairo
Africa/Bissau Africa/Bissau
Africa/Nairobi Africa/Nairobi
Africa/Addis_Ababa
Africa/Asmara
Africa/Dar_es_Salaam
Africa/Djibouti
Africa/Kampala
Africa/Mogadishu
Indian/Antananarivo
Indian/Comoro
Indian/Mayotte
Africa/Monrovia Africa/Monrovia
Africa/Tripoli Africa/Tripoli
Indian/Mauritius Indian/Mauritius
Africa/Casablanca Africa/Casablanca
Africa/El_Aaiun Africa/El_Aaiun
Africa/Maputo Africa/Maputo
Africa/Blantyre
Africa/Bujumbura
Africa/Gaborone
Africa/Harare
Africa/Kigali
Africa/Lubumbashi
Africa/Lusaka
Africa/Windhoek Africa/Windhoek
Africa/Lagos Africa/Lagos
Africa/Bangui
Africa/Brazzaville
Africa/Douala
Africa/Kinshasa
Africa/Libreville
Africa/Luanda
Africa/Malabo
Africa/Niamey
Africa/Porto-Novo
Indian/Reunion Indian/Reunion
Africa/Sao_Tome Africa/Sao_Tome
Indian/Mahe Indian/Mahe
Africa/Johannesburg Africa/Johannesburg
Africa/Maseru
Africa/Mbabane
Africa/Khartoum Africa/Khartoum
Africa/Juba Africa/Juba
Africa/Tunis Africa/Tunis
@ -79,7 +42,6 @@ Asia/Taipei
Asia/Macau Asia/Macau
Asia/Nicosia Asia/Nicosia
Asia/Famagusta Asia/Famagusta
Europe/Nicosia
Asia/Tbilisi Asia/Tbilisi
Asia/Dili Asia/Dili
Asia/Kolkata Asia/Kolkata
@ -115,21 +77,14 @@ Asia/Gaza
Asia/Hebron Asia/Hebron
Asia/Manila Asia/Manila
Asia/Qatar Asia/Qatar
Asia/Bahrain
Asia/Riyadh Asia/Riyadh
Antarctica/Syowa
Asia/Aden
Asia/Kuwait
Asia/Singapore Asia/Singapore
Asia/Colombo Asia/Colombo
Asia/Damascus Asia/Damascus
Asia/Dushanbe Asia/Dushanbe
Asia/Bangkok Asia/Bangkok
Asia/Phnom_Penh
Asia/Vientiane
Asia/Ashgabat Asia/Ashgabat
Asia/Dubai Asia/Dubai
Asia/Muscat
Asia/Samarkand Asia/Samarkand
Asia/Tashkent Asia/Tashkent
Asia/Ho_Chi_Minh Asia/Ho_Chi_Minh
@ -152,7 +107,6 @@ Pacific/Gambier
Pacific/Marquesas Pacific/Marquesas
Pacific/Tahiti Pacific/Tahiti
Pacific/Guam Pacific/Guam
Pacific/Saipan
Pacific/Tarawa Pacific/Tarawa
Pacific/Kanton Pacific/Kanton
Pacific/Kiritimati Pacific/Kiritimati
@ -165,17 +119,14 @@ Pacific/Nauru
Pacific/Noumea Pacific/Noumea
Pacific/Auckland Pacific/Auckland
Pacific/Chatham Pacific/Chatham
Antarctica/McMurdo
Pacific/Rarotonga Pacific/Rarotonga
Pacific/Niue Pacific/Niue
Pacific/Norfolk Pacific/Norfolk
Pacific/Palau Pacific/Palau
Pacific/Port_Moresby Pacific/Port_Moresby
Antarctica/DumontDUrville
Pacific/Bougainville Pacific/Bougainville
Pacific/Pitcairn Pacific/Pitcairn
Pacific/Pago_Pago Pacific/Pago_Pago
Pacific/Midway
Pacific/Apia Pacific/Apia
Pacific/Guadalcanal Pacific/Guadalcanal
Pacific/Fakaofo Pacific/Fakaofo
@ -185,9 +136,6 @@ Pacific/Wake
Pacific/Efate Pacific/Efate
Pacific/Wallis Pacific/Wallis
Europe/London Europe/London
Europe/Jersey
Europe/Guernsey
Europe/Isle_of_Man
Europe/Dublin Europe/Dublin
WET WET
CET CET
@ -208,19 +156,14 @@ America/Nuuk
America/Thule America/Thule
Europe/Tallinn Europe/Tallinn
Europe/Helsinki Europe/Helsinki
Europe/Mariehamn
Europe/Paris Europe/Paris
Europe/Berlin Europe/Berlin
Europe/Busingen
Europe/Gibraltar Europe/Gibraltar
Europe/Athens Europe/Athens
Europe/Budapest Europe/Budapest
Atlantic/Reykjavik Atlantic/Reykjavik
Europe/Rome Europe/Rome
Europe/Vatican
Europe/San_Marino
Europe/Riga Europe/Riga
Europe/Vaduz
Europe/Vilnius Europe/Vilnius
Europe/Luxembourg Europe/Luxembourg
Europe/Malta Europe/Malta
@ -228,7 +171,6 @@ Europe/Chisinau
Europe/Monaco Europe/Monaco
Europe/Amsterdam Europe/Amsterdam
Europe/Oslo Europe/Oslo
Arctic/Longyearbyen
Europe/Warsaw Europe/Warsaw
Europe/Lisbon Europe/Lisbon
Atlantic/Azores Atlantic/Azores
@ -262,19 +204,12 @@ Asia/Ust-Nera
Asia/Kamchatka Asia/Kamchatka
Asia/Anadyr Asia/Anadyr
Europe/Belgrade Europe/Belgrade
Europe/Ljubljana
Europe/Podgorica
Europe/Sarajevo
Europe/Skopje
Europe/Zagreb
Europe/Bratislava
Europe/Madrid Europe/Madrid
Africa/Ceuta Africa/Ceuta
Atlantic/Canary Atlantic/Canary
Europe/Stockholm Europe/Stockholm
Europe/Zurich Europe/Zurich
Europe/Istanbul Europe/Istanbul
Asia/Istanbul
Europe/Kiev Europe/Kiev
Europe/Uzhgorod Europe/Uzhgorod
Europe/Zaporozhye Europe/Zaporozhye
@ -301,7 +236,6 @@ America/Nome
America/Adak America/Adak
Pacific/Honolulu Pacific/Honolulu
America/Phoenix America/Phoenix
America/Creston
America/Boise America/Boise
America/Indiana/Indianapolis America/Indiana/Indianapolis
America/Indiana/Marengo America/Indiana/Marengo
@ -321,7 +255,6 @@ America/Halifax
America/Glace_Bay America/Glace_Bay
America/Moncton America/Moncton
America/Toronto America/Toronto
America/Nassau
America/Thunder_Bay America/Thunder_Bay
America/Nipigon America/Nipigon
America/Rainy_River America/Rainy_River
@ -366,28 +299,7 @@ America/Jamaica
America/Martinique America/Martinique
America/Managua America/Managua
America/Panama America/Panama
America/Atikokan
America/Cayman
America/Puerto_Rico America/Puerto_Rico
America/Anguilla
America/Antigua
America/Aruba
America/Curacao
America/Blanc-Sablon
America/Dominica
America/Grenada
America/Guadeloupe
America/Kralendijk
America/Lower_Princes
America/Marigot
America/Montserrat
America/Port_of_Spain
America/St_Barthelemy
America/St_Kitts
America/St_Lucia
America/St_Thomas
America/St_Vincent
America/Tortola
America/Miquelon America/Miquelon
America/Grand_Turk America/Grand_Turk
America/Argentina/Buenos_Aires America/Argentina/Buenos_Aires
@ -471,46 +383,114 @@ Etc/GMT+10
Etc/GMT+11 Etc/GMT+11
Etc/GMT+12 Etc/GMT+12
Factory Factory
Africa/Accra
Africa/Addis_Ababa
Africa/Asmara
Africa/Asmera Africa/Asmera
Africa/Bamako
Africa/Bangui
Africa/Banjul
Africa/Blantyre
Africa/Brazzaville
Africa/Bujumbura
Africa/Conakry
Africa/Dakar
Africa/Dar_es_Salaam
Africa/Djibouti
Africa/Douala
Africa/Freetown
Africa/Gaborone
Africa/Harare
Africa/Kampala
Africa/Kigali
Africa/Kinshasa
Africa/Libreville
Africa/Lome
Africa/Luanda
Africa/Lubumbashi
Africa/Lusaka
Africa/Malabo
Africa/Maseru
Africa/Mbabane
Africa/Mogadishu
Africa/Niamey
Africa/Nouakchott
Africa/Ouagadougou
Africa/Porto-Novo
Africa/Timbuktu Africa/Timbuktu
America/Anguilla
America/Antigua
America/Argentina/ComodRivadavia America/Argentina/ComodRivadavia
America/Aruba
America/Atikokan
America/Atka America/Atka
America/Blanc-Sablon
America/Buenos_Aires America/Buenos_Aires
America/Catamarca America/Catamarca
America/Cayman
America/Coral_Harbour America/Coral_Harbour
America/Cordoba America/Cordoba
America/Creston
America/Curacao
America/Dominica
America/Ensenada America/Ensenada
America/Fort_Wayne America/Fort_Wayne
America/Godthab America/Godthab
America/Grenada
America/Guadeloupe
America/Indianapolis America/Indianapolis
America/Jujuy America/Jujuy
America/Knox_IN America/Knox_IN
America/Kralendijk
America/Louisville America/Louisville
America/Lower_Princes
America/Marigot
America/Mendoza America/Mendoza
America/Montreal America/Montreal
America/Montserrat
America/Nassau
America/Port_of_Spain
America/Porto_Acre America/Porto_Acre
America/Rosario America/Rosario
America/Santa_Isabel America/Santa_Isabel
America/Shiprock America/Shiprock
America/St_Barthelemy
America/St_Kitts
America/St_Lucia
America/St_Thomas
America/St_Vincent
America/Tortola
America/Virgin America/Virgin
Antarctica/DumontDUrville
Antarctica/McMurdo
Antarctica/South_Pole Antarctica/South_Pole
Antarctica/Syowa
Arctic/Longyearbyen
Asia/Aden
Asia/Ashkhabad Asia/Ashkhabad
Asia/Bahrain
Asia/Calcutta Asia/Calcutta
Asia/Chongqing Asia/Chongqing
Asia/Chungking Asia/Chungking
Asia/Dacca Asia/Dacca
Asia/Harbin Asia/Harbin
Asia/Istanbul
Asia/Kashgar Asia/Kashgar
Asia/Katmandu Asia/Katmandu
Asia/Kuwait
Asia/Macao Asia/Macao
Asia/Muscat
Asia/Phnom_Penh
Asia/Rangoon Asia/Rangoon
Asia/Saigon Asia/Saigon
Asia/Tel_Aviv Asia/Tel_Aviv
Asia/Thimbu Asia/Thimbu
Asia/Ujung_Pandang Asia/Ujung_Pandang
Asia/Ulan_Bator Asia/Ulan_Bator
Asia/Vientiane
Atlantic/Faeroe Atlantic/Faeroe
Atlantic/Jan_Mayen Atlantic/Jan_Mayen
Atlantic/St_Helena
Australia/ACT Australia/ACT
Australia/Canberra Australia/Canberra
Australia/Currie Australia/Currie
@ -542,7 +522,22 @@ Egypt
Eire Eire
Etc/UCT Etc/UCT
Europe/Belfast Europe/Belfast
Europe/Bratislava
Europe/Busingen
Europe/Guernsey
Europe/Isle_of_Man
Europe/Jersey
Europe/Ljubljana
Europe/Mariehamn
Europe/Nicosia
Europe/Podgorica
Europe/San_Marino
Europe/Sarajevo
Europe/Skopje
Europe/Tiraspol Europe/Tiraspol
Europe/Vaduz
Europe/Vatican
Europe/Zagreb
GB GB
GB-Eire GB-Eire
GMT+0 GMT+0
@ -551,6 +546,9 @@ GMT0
Greenwich Greenwich
Hongkong Hongkong
Iceland Iceland
Indian/Antananarivo
Indian/Comoro
Indian/Mayotte
Iran Iran
Israel Israel
Jamaica Jamaica
@ -566,7 +564,9 @@ Navajo
PRC PRC
Pacific/Enderbury Pacific/Enderbury
Pacific/Johnston Pacific/Johnston
Pacific/Midway
Pacific/Ponape Pacific/Ponape
Pacific/Saipan
Pacific/Samoa Pacific/Samoa
Pacific/Truk Pacific/Truk
Pacific/Yap Pacific/Yap

View file

@ -1,13 +1,5 @@
import sys import sys
if sys.platform == 'win32':
if sys.platform == "win32": from tzlocal.win32 import get_localzone, reload_localzone
from tzlocal.win32 import (
get_localzone,
get_localzone_name,
reload_localzone,
) # pragma: no cover
else: else:
from tzlocal.unix import get_localzone, get_localzone_name, reload_localzone from tzlocal.unix import get_localzone, reload_localzone
__all__ = ["get_localzone", "get_localzone_name", "reload_localzone"]

View file

@ -1,75 +1,97 @@
import os import os
import pytz
import re import re
import sys
import warnings import warnings
from datetime import timezone
import pytz_deprecation_shim as pds
from tzlocal import utils from tzlocal import utils
if sys.version_info >= (3, 9):
from zoneinfo import ZoneInfo # pragma: no cover
else:
from backports.zoneinfo import ZoneInfo # pragma: no cover
_cache_tz = None _cache_tz = None
_cache_tz_name = None
def _get_localzone_name(_root="/"): def _tz_from_env(tzenv):
if tzenv[0] == ':':
tzenv = tzenv[1:]
# TZ specifies a file
if os.path.isabs(tzenv) and os.path.exists(tzenv):
with open(tzenv, 'rb') as tzfile:
return pytz.tzfile.build_tzinfo('local', tzfile)
# TZ specifies a zoneinfo zone.
try:
tz = pytz.timezone(tzenv)
# That worked, so we return this:
return tz
except pytz.UnknownTimeZoneError:
raise pytz.UnknownTimeZoneError(
"tzlocal() does not support non-zoneinfo timezones like %s. \n"
"Please use a timezone in the form of Continent/City")
def _try_tz_from_env():
tzenv = os.environ.get('TZ')
if tzenv:
try:
return _tz_from_env(tzenv)
except pytz.UnknownTimeZoneError:
pass
def _get_localzone(_root='/'):
"""Tries to find the local timezone configuration. """Tries to find the local timezone configuration.
This method finds the timezone name, if it can, or it returns None. This method prefers finding the timezone name and passing that to 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 The parameter _root makes the function look for files like /etc/localtime
beneath the _root directory. This is primarily used by the tests. beneath the _root directory. This is primarily used by the tests.
In normal usage you call the function without parameters.""" In normal usage you call the function without parameters."""
# First try the ENV setting. tzenv = _try_tz_from_env()
tzenv = utils._tz_name_from_env()
if tzenv: if tzenv:
return tzenv return tzenv
# Are we under Termux on Android? # Are we under Termux on Android?
if os.path.exists(os.path.join(_root, "system/bin/getprop")): if os.path.exists('/system/bin/getprop'):
import subprocess import subprocess
androidtz = subprocess.check_output(['getprop', 'persist.sys.timezone']).strip().decode()
androidtz = ( return pytz.timezone(androidtz)
subprocess.check_output(["getprop", "persist.sys.timezone"])
.strip()
.decode()
)
return androidtz
# Now look for distribution specific configuration files # Now look for distribution specific configuration files
# that contain the timezone name. # that contain the timezone name.
for configfile in ('etc/timezone', 'var/db/zoneinfo'):
# Stick all of them in a dict, to compare later.
found_configs = {}
for configfile in ("etc/timezone", "var/db/zoneinfo"):
tzpath = os.path.join(_root, configfile) tzpath = os.path.join(_root, configfile)
try: try:
with open(tzpath, "rt") as tzfile: with open(tzpath, 'rb') as tzfile:
data = tzfile.read() data = tzfile.read()
etctz = data.strip('/ \t\r\n') # Issue #3 was that /etc/timezone was a zoneinfo file.
# That's a misconfiguration, but we need to handle it gracefully:
if data[:5] == b'TZif2':
continue
etctz = data.strip().decode()
if not etctz: if not etctz:
# Empty file, skip # Empty file, skip
continue continue
for etctz in etctz.splitlines(): for etctz in data.decode().splitlines():
# Get rid of host definitions and comments: # Get rid of host definitions and comments:
if " " in etctz: if ' ' in etctz:
etctz, dummy = etctz.split(" ", 1) etctz, dummy = etctz.split(' ', 1)
if "#" in etctz: if '#' in etctz:
etctz, dummy = etctz.split("#", 1) etctz, dummy = etctz.split('#', 1)
if not etctz: if not etctz:
continue continue
tz = pytz.timezone(etctz.replace(' ', '_'))
if _root == '/':
# We are using a file in etc to name the timezone.
# Verify that the timezone specified there is actually used:
utils.assert_tz_offset(tz)
return tz
found_configs[tzpath] = etctz.replace(" ", "_") except IOError:
# File doesn't exist or is a directory
except (IOError, UnicodeDecodeError):
# File doesn't exist or is a directory, or it's a binary file.
continue continue
# CentOS has a ZONE setting in /etc/sysconfig/clock, # CentOS has a ZONE setting in /etc/sysconfig/clock,
@ -77,14 +99,14 @@ def _get_localzone_name(_root="/"):
# Gentoo has a TIMEZONE setting in /etc/conf.d/clock # Gentoo has a TIMEZONE setting in /etc/conf.d/clock
# We look through these files for a timezone: # We look through these files for a timezone:
zone_re = re.compile(r"\s*ZONE\s*=\s*\"") zone_re = re.compile(r'\s*ZONE\s*=\s*\"')
timezone_re = re.compile(r"\s*TIMEZONE\s*=\s*\"") timezone_re = re.compile(r'\s*TIMEZONE\s*=\s*\"')
end_re = re.compile('"') end_re = re.compile('\"')
for filename in ("etc/sysconfig/clock", "etc/conf.d/clock"): for filename in ('etc/sysconfig/clock', 'etc/conf.d/clock'):
tzpath = os.path.join(_root, filename) tzpath = os.path.join(_root, filename)
try: try:
with open(tzpath, "rt") as tzfile: with open(tzpath, 'rt') as tzfile:
data = tzfile.readlines() data = tzfile.readlines()
for line in data: for line in data:
@ -96,108 +118,48 @@ def _get_localzone_name(_root="/"):
if match is not None: if match is not None:
# Some setting existed # Some setting existed
line = line[match.end():] line = line[match.end():]
etctz = line[: end_re.search(line).start()] etctz = line[:end_re.search(line).start()]
# We found a timezone # We found a timezone
found_configs[tzpath] = etctz.replace(" ", "_") tz = pytz.timezone(etctz.replace(' ', '_'))
if _root == '/':
except (IOError, UnicodeDecodeError):
# UnicodeDecode handles when clock is symlink to /etc/localtime
continue
# 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.exists(tzpath) and os.path.islink(tzpath):
etctz = realtzpath = os.path.realpath(tzpath)
start = etctz.find("/") + 1
while start != 0:
etctz = etctz[start:]
try:
pds.timezone(etctz)
tzinfo = f"{tzpath} is a symlink to"
found_configs[tzinfo] = etctz.replace(" ", "_")
except pds.UnknownTimeZoneError:
pass
start = etctz.find("/") + 1
if len(found_configs) > 0:
# We found some explicit config of some sort!
if len(found_configs) > 1:
# Uh-oh, multiple configs. See if they match:
unique_tzs = set()
zoneinfo = os.path.join(_root, "usr", "share", "zoneinfo")
directory_depth = len(zoneinfo.split(os.path.sep))
for tzname in found_configs.values():
# Look them up in /usr/share/zoneinfo, and find what they
# really point to:
path = os.path.realpath(os.path.join(zoneinfo, *tzname.split("/")))
real_zone_name = "/".join(path.split(os.path.sep)[directory_depth:])
unique_tzs.add(real_zone_name)
if len(unique_tzs) != 1:
message = "Multiple conflicting time zone configurations found:\n"
for key, value in found_configs.items():
message += f"{key}: {value}\n"
message += "Fix the configuration, or set the time zone in a TZ environment variable.\n"
raise utils.ZoneInfoNotFoundError(message)
# We found exactly one config! Use it.
return list(found_configs.values())[0]
def _get_localzone(_root="/"):
"""Creates a timezone object from the timezone name.
If there is no timezone config, it will try to create a file from the
localtime timezone, and if there isn't one, it will default to UTC.
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."""
# First try the ENV setting.
tzenv = utils._tz_from_env()
if tzenv:
return tzenv
tzname = _get_localzone_name(_root)
if tzname is None:
# 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
with open(tzpath, "rb") as tzfile:
tz = pds.wrap_zone(ZoneInfo.from_file(tzfile, key="local"))
break
else:
warnings.warn("Can not find any timezone configuration, defaulting to UTC.")
tz = timezone.utc
else:
tz = pds.timezone(tzname)
if _root == "/":
# We are using a file in etc to name the timezone. # We are using a file in etc to name the timezone.
# Verify that the timezone specified there is actually used: # Verify that the timezone specified there is actually used:
utils.assert_tz_offset(tz) utils.assert_tz_offset(tz)
return tz return tz
except IOError:
# File doesn't exist or is a directory
continue
def get_localzone_name(): # systemd distributions use symlinks that include the zone name,
"""Get the computers configured local timezone name, if any.""" # see manpage of localtime(5) and timedatectl(1)
global _cache_tz_name tzpath = os.path.join(_root, 'etc/localtime')
if _cache_tz_name is None: if os.path.exists(tzpath) and os.path.islink(tzpath):
_cache_tz_name = _get_localzone_name() tzpath = os.path.realpath(tzpath)
start = tzpath.find("/")+1
while start != 0:
tzpath = tzpath[start:]
try:
return pytz.timezone(tzpath)
except pytz.UnknownTimeZoneError:
pass
start = tzpath.find("/")+1
return _cache_tz_name # 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
with open(tzpath, 'rb') as tzfile:
return pytz.tzfile.build_tzinfo('local', tzfile)
warnings.warn('Can not find any timezone configuration, defaulting to UTC.')
return pytz.utc
def get_localzone(): def get_localzone():
"""Get the computers configured local timezone, if any.""" """Get the computers configured local timezone, if any."""
global _cache_tz global _cache_tz
if _cache_tz is None: if _cache_tz is None:
_cache_tz = _get_localzone() _cache_tz = _get_localzone()
@ -207,9 +169,6 @@ def get_localzone():
def reload_localzone(): def reload_localzone():
"""Reload the cached localzone. You need to call this if the timezone has changed.""" """Reload the cached localzone. You need to call this if the timezone has changed."""
global _cache_tz_name
global _cache_tz global _cache_tz
_cache_tz_name = _get_localzone_name()
_cache_tz = _get_localzone() _cache_tz = _get_localzone()
return _cache_tz return _cache_tz

View file

@ -1,24 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os
import time import time
import datetime import datetime
import calendar import calendar
import pytz_deprecation_shim as pds
try:
import zoneinfo # pragma: no cover
except ImportError:
from backports import zoneinfo # pragma: no cover
from tzlocal import windows_tz
class ZoneInfoNotFoundError(pds.UnknownTimeZoneError, zoneinfo.ZoneInfoNotFoundError):
"""An exception derived from both pytz and zoneinfo
This exception will be trappable both by pytz expecting clients and
zoneinfo expecting clients.
"""
def get_system_offset(): def get_system_offset():
@ -38,9 +21,9 @@ def get_system_offset():
# so we check that the difference is less than one minute, because nobody # so we check that the difference is less than one minute, because nobody
# has that small DST differences. # has that small DST differences.
if abs(offset - time.altzone) < 60: if abs(offset - time.altzone) < 60:
return -time.altzone # pragma: no cover return -time.altzone
else: else:
return -time.timezone # pragma: no cover return -time.timezone
def get_tz_offset(tz): def get_tz_offset(tz):
@ -56,70 +39,8 @@ def assert_tz_offset(tz):
tz_offset = get_tz_offset(tz) tz_offset = get_tz_offset(tz)
system_offset = get_system_offset() system_offset = get_system_offset()
if tz_offset != system_offset: if tz_offset != system_offset:
msg = ( msg = ('Timezone offset does not match system offset: {0} != {1}. '
"Timezone offset does not match system offset: {} != {}. " 'Please, check your config files.').format(
"Please, check your config files." tz_offset, system_offset
).format(tz_offset, system_offset) )
raise ValueError(msg) raise ValueError(msg)
def _tz_name_from_env(tzenv=None):
if tzenv is None:
tzenv = os.environ.get("TZ")
if not tzenv:
return None
if tzenv in windows_tz.tz_win:
# Yup, it's a timezone
return tzenv
if os.path.isabs(tzenv) and os.path.exists(tzenv):
# It's a file specification
parts = tzenv.split(os.sep)
# Is it a zone info zone?
possible_tz = "/".join(parts[-2:])
if possible_tz in windows_tz.tz_win:
# Yup, it is
return possible_tz
# Maybe it's a short one, like UTC?
if parts[-1] in windows_tz.tz_win:
# Indeed
return parts[-1]
def _tz_from_env(tzenv=None):
if tzenv is None:
tzenv = os.environ.get("TZ")
if not tzenv:
return None
# Some weird format that exists:
if tzenv[0] == ":":
tzenv = tzenv[1:]
# TZ specifies a file
if os.path.isabs(tzenv) and os.path.exists(tzenv):
# Try to see if we can figure out the name
tzname = _tz_name_from_env(tzenv)
if not tzname:
# Nope, not a standard timezone name, just take the filename
tzname = tzenv.split(os.sep)[-1]
with open(tzenv, "rb") as tzfile:
zone = zoneinfo.ZoneInfo.from_file(tzfile, key=tzname)
return pds.wrap_zone(zone)
# TZ must specify a zoneinfo zone.
try:
tz = pds.timezone(tzenv)
# That worked, so we return this:
return tz
except pds.UnknownTimeZoneError:
# Nope, it's something like "PST4DST" etc, we can't handle that.
raise ZoneInfoNotFoundError(
"tzlocal() does not support non-zoneinfo timezones like %s. \n"
"Please use a timezone in the form of Continent/City"
) from None

View file

@ -1,53 +1,32 @@
from datetime import datetime
import pytz_deprecation_shim as pds
try: try:
import _winreg as winreg import _winreg as winreg
except ImportError: except ImportError:
import winreg import winreg
import pytz
from tzlocal.windows_tz import win_tz from tzlocal.windows_tz import win_tz
from tzlocal import utils from tzlocal import utils
_cache_tz = None _cache_tz = None
_cache_tz_name = None
def valuestodict(key): def valuestodict(key):
"""Convert a registry key's values to a dictionary.""" """Convert a registry key's values to a dictionary."""
result = {} dict = {}
size = winreg.QueryInfoKey(key)[1] size = winreg.QueryInfoKey(key)[1]
for i in range(size): for i in range(size):
data = winreg.EnumValue(key, i) data = winreg.EnumValue(key, i)
result[data[0]] = data[1] dict[data[0]] = data[1]
return result return dict
def _get_dst_info(tz): def get_localzone_name():
# 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 # Windows is special. It has unique time zone names (in several
# meanings of the word) available, but unfortunately, they can be # meanings of the word) available, but unfortunately, they can be
# translated to the language of the operating system, so we need to # 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 # do a backwards lookup, by going through all time zones and see which
# one matches. # one matches.
tzenv = utils._tz_name_from_env()
if tzenv:
return tzenv
handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
TZLOCALKEYNAME = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation" TZLOCALKEYNAME = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation"
@ -55,16 +34,44 @@ def _get_localzone_name():
keyvalues = valuestodict(localtz) keyvalues = valuestodict(localtz)
localtz.Close() localtz.Close()
if "TimeZoneKeyName" in keyvalues: if 'TimeZoneKeyName' in keyvalues:
# Windows 7 and later # Windows 7 (and Vista?)
# For some reason this returns a string with loads of NUL bytes at # 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 # least on some systems. I don't know if this is a bug somewhere, I
# just work around it. # just work around it.
tzkeyname = keyvalues["TimeZoneKeyName"].split("\x00", 1)[0] tzkeyname = keyvalues['TimeZoneKeyName'].split('\x00', 1)[0]
else: else:
# Don't support XP any longer # Windows 2000 or XP
raise LookupError("Can not find Windows timezone configuration")
# 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()
try:
if data['Std'] == tzwin:
tzkeyname = subkey
break
except KeyError:
# This timezone didn't have proper configuration.
# Ignore it.
pass
tzkey.Close()
handle.Close()
if tzkeyname is None:
raise LookupError('Can not find Windows timezone configuration')
timezone = win_tz.get(tzkeyname) timezone = win_tz.get(tzkeyname)
if timezone is None: if timezone is None:
@ -74,64 +81,24 @@ def _get_localzone_name():
# Return what we have. # Return what we have.
if timezone is None: if timezone is None:
raise utils.ZoneInfoNotFoundError(tzkeyname) raise pytz.UnknownTimeZoneError('Can not find timezone ' + tzkeyname)
if keyvalues.get("DynamicDaylightTimeDisabled", 0) == 1:
# DST is disabled, so don't return the timezone name,
# instead return Etc/GMT+offset
tz = pds.timezone(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 utils.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 utils.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 return timezone
def get_localzone_name():
"""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(): def get_localzone():
"""Returns the zoneinfo-based tzinfo object that matches the Windows-configured timezone.""" """Returns the zoneinfo-based tzinfo object that matches the Windows-configured timezone."""
global _cache_tz global _cache_tz
if _cache_tz is None: if _cache_tz is None:
_cache_tz = pds.timezone(get_localzone_name()) _cache_tz = pytz.timezone(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) utils.assert_tz_offset(_cache_tz)
return _cache_tz return _cache_tz
def reload_localzone(): def reload_localzone():
"""Reload the cached localzone. You need to call this if the timezone has changed.""" """Reload the cached localzone. You need to call this if the timezone has changed."""
global _cache_tz global _cache_tz
global _cache_tz_name _cache_tz = pytz.timezone(get_localzone_name())
_cache_tz_name = _get_localzone_name()
_cache_tz = pds.timezone(_cache_tz_name)
utils.assert_tz_offset(_cache_tz) utils.assert_tz_offset(_cache_tz)
return _cache_tz return _cache_tz

View file

@ -104,7 +104,6 @@ win_tz = {'AUS Central Standard Time': 'Australia/Darwin',
'Saratov Standard Time': 'Europe/Saratov', 'Saratov Standard Time': 'Europe/Saratov',
'Singapore Standard Time': 'Asia/Singapore', 'Singapore Standard Time': 'Asia/Singapore',
'South Africa Standard Time': 'Africa/Johannesburg', 'South Africa Standard Time': 'Africa/Johannesburg',
'South Sudan Standard Time': 'Africa/Juba',
'Sri Lanka Standard Time': 'Asia/Colombo', 'Sri Lanka Standard Time': 'Asia/Colombo',
'Sudan Standard Time': 'Africa/Khartoum', 'Sudan Standard Time': 'Africa/Khartoum',
'Syria Standard Time': 'Asia/Damascus', 'Syria Standard Time': 'Asia/Damascus',
@ -119,7 +118,7 @@ win_tz = {'AUS Central Standard Time': 'Australia/Darwin',
'Turks And Caicos Standard Time': 'America/Grand_Turk', 'Turks And Caicos Standard Time': 'America/Grand_Turk',
'US Eastern Standard Time': 'America/Indianapolis', 'US Eastern Standard Time': 'America/Indianapolis',
'US Mountain Standard Time': 'America/Phoenix', 'US Mountain Standard Time': 'America/Phoenix',
'UTC': 'Etc/UTC', 'UTC': 'Etc/GMT',
'UTC+12': 'Etc/GMT-12', 'UTC+12': 'Etc/GMT-12',
'UTC+13': 'Etc/GMT-13', 'UTC+13': 'Etc/GMT-13',
'UTC-02': 'Etc/GMT+2', 'UTC-02': 'Etc/GMT+2',
@ -137,8 +136,7 @@ win_tz = {'AUS Central Standard Time': 'Australia/Darwin',
'West Asia Standard Time': 'Asia/Tashkent', 'West Asia Standard Time': 'Asia/Tashkent',
'West Bank Standard Time': 'Asia/Hebron', 'West Bank Standard Time': 'Asia/Hebron',
'West Pacific Standard Time': 'Pacific/Port_Moresby', 'West Pacific Standard Time': 'Pacific/Port_Moresby',
'Yakutsk Standard Time': 'Asia/Yakutsk', 'Yakutsk Standard Time': 'Asia/Yakutsk'}
'Yukon Standard Time': 'America/Whitehorse'}
# Old name for the win_tz variable: # Old name for the win_tz variable:
tz_names = win_tz tz_names = win_tz
@ -168,7 +166,7 @@ tz_win = {'Africa/Abidjan': 'Greenwich Standard Time',
'Africa/Gaborone': 'South Africa Standard Time', 'Africa/Gaborone': 'South Africa Standard Time',
'Africa/Harare': 'South Africa Standard Time', 'Africa/Harare': 'South Africa Standard Time',
'Africa/Johannesburg': 'South Africa Standard Time', 'Africa/Johannesburg': 'South Africa Standard Time',
'Africa/Juba': 'South Sudan Standard Time', 'Africa/Juba': 'E. Africa Standard Time',
'Africa/Kampala': 'E. Africa Standard Time', 'Africa/Kampala': 'E. Africa Standard Time',
'Africa/Khartoum': 'Sudan Standard Time', 'Africa/Khartoum': 'Sudan Standard Time',
'Africa/Kigali': 'South Africa Standard Time', 'Africa/Kigali': 'South Africa Standard Time',
@ -236,8 +234,8 @@ tz_win = {'Africa/Abidjan': 'Greenwich Standard Time',
'America/Creston': 'US Mountain Standard Time', 'America/Creston': 'US Mountain Standard Time',
'America/Cuiaba': 'Central Brazilian Standard Time', 'America/Cuiaba': 'Central Brazilian Standard Time',
'America/Curacao': 'SA Western Standard Time', 'America/Curacao': 'SA Western Standard Time',
'America/Danmarkshavn': 'Greenwich Standard Time', 'America/Danmarkshavn': 'UTC',
'America/Dawson': 'Yukon Standard Time', 'America/Dawson': 'Pacific Standard Time',
'America/Dawson_Creek': 'US Mountain Standard Time', 'America/Dawson_Creek': 'US Mountain Standard Time',
'America/Denver': 'Mountain Standard Time', 'America/Denver': 'Mountain Standard Time',
'America/Detroit': 'Eastern Standard Time', 'America/Detroit': 'Eastern Standard Time',
@ -347,14 +345,14 @@ tz_win = {'Africa/Abidjan': 'Greenwich Standard Time',
'America/Tortola': 'SA Western Standard Time', 'America/Tortola': 'SA Western Standard Time',
'America/Vancouver': 'Pacific Standard Time', 'America/Vancouver': 'Pacific Standard Time',
'America/Virgin': 'SA Western Standard Time', 'America/Virgin': 'SA Western Standard Time',
'America/Whitehorse': 'Yukon Standard Time', 'America/Whitehorse': 'Pacific Standard Time',
'America/Winnipeg': 'Central Standard Time', 'America/Winnipeg': 'Central Standard Time',
'America/Yakutat': 'Alaskan Standard Time', 'America/Yakutat': 'Alaskan Standard Time',
'America/Yellowknife': 'Mountain Standard Time', 'America/Yellowknife': 'Mountain Standard Time',
'Antarctica/Casey': 'Central Pacific Standard Time', 'Antarctica/Casey': 'Singapore Standard Time',
'Antarctica/Davis': 'SE Asia Standard Time', 'Antarctica/Davis': 'SE Asia Standard Time',
'Antarctica/DumontDUrville': 'West Pacific Standard Time', 'Antarctica/DumontDUrville': 'West Pacific Standard Time',
'Antarctica/Macquarie': 'Tasmania Standard Time', 'Antarctica/Macquarie': 'Central Pacific Standard Time',
'Antarctica/Mawson': 'West Asia Standard Time', 'Antarctica/Mawson': 'West Asia Standard Time',
'Antarctica/McMurdo': 'New Zealand Standard Time', 'Antarctica/McMurdo': 'New Zealand Standard Time',
'Antarctica/Palmer': 'SA Eastern Standard Time', 'Antarctica/Palmer': 'SA Eastern Standard Time',
@ -503,7 +501,7 @@ tz_win = {'Africa/Abidjan': 'Greenwich Standard Time',
'Canada/Newfoundland': 'Newfoundland Standard Time', 'Canada/Newfoundland': 'Newfoundland Standard Time',
'Canada/Pacific': 'Pacific Standard Time', 'Canada/Pacific': 'Pacific Standard Time',
'Canada/Saskatchewan': 'Canada Central Standard Time', 'Canada/Saskatchewan': 'Canada Central Standard Time',
'Canada/Yukon': 'Yukon Standard Time', 'Canada/Yukon': 'Pacific Standard Time',
'Chile/Continental': 'Pacific SA Standard Time', 'Chile/Continental': 'Pacific SA Standard Time',
'Chile/EasterIsland': 'Easter Island Standard Time', 'Chile/EasterIsland': 'Easter Island Standard Time',
'Cuba': 'Cuba Standard Time', 'Cuba': 'Cuba Standard Time',