diff --git a/lib/pytz/LICENSE.txt b/lib/pytz/LICENSE.txt deleted file mode 100644 index 7c901fd2..00000000 --- a/lib/pytz/LICENSE.txt +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2003-2018 Stuart Bishop - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/lib/pytz/README.txt b/lib/pytz/README.txt deleted file mode 100644 index d9b03902..00000000 --- a/lib/pytz/README.txt +++ /dev/null @@ -1,587 +0,0 @@ -pytz - World Timezone Definitions for Python -============================================ - -:Author: Stuart Bishop - -Introduction -~~~~~~~~~~~~ - -pytz brings the Olson tz database into Python. This library allows -accurate and cross platform timezone calculations using Python 2.4 -or higher. It also solves the issue of ambiguous times at the end -of daylight saving time, which you can read more about in the Python -Library Reference (``datetime.tzinfo``). - -Almost all of the Olson timezones are supported. - -.. note:: - - This library differs from the documented Python API for - tzinfo implementations; if you want to create local wallclock - times you need to use the ``localize()`` method documented in this - document. In addition, if you perform date arithmetic on local - times that cross DST boundaries, the result may be in an incorrect - timezone (ie. subtract 1 minute from 2002-10-27 1:00 EST and you get - 2002-10-27 0:59 EST instead of the correct 2002-10-27 1:59 EDT). A - ``normalize()`` method is provided to correct this. Unfortunately these - issues cannot be resolved without modifying the Python datetime - implementation (see PEP-431). - - -Installation -~~~~~~~~~~~~ - -This package can either be installed from a .egg file using setuptools, -or from the tarball using the standard Python distutils. - -If you are installing from a tarball, run the following command as an -administrative user:: - - python setup.py install - -If you are installing using setuptools, you don't even need to download -anything as the latest version will be downloaded for you -from the Python package index:: - - easy_install --upgrade pytz - -If you already have the .egg file, you can use that too:: - - easy_install pytz-2008g-py2.6.egg - - -Example & Usage -~~~~~~~~~~~~~~~ - -Localized times and date arithmetic ------------------------------------ - ->>> from datetime import datetime, timedelta ->>> from pytz import timezone ->>> import pytz ->>> utc = pytz.utc ->>> utc.zone -'UTC' ->>> eastern = timezone('US/Eastern') ->>> eastern.zone -'US/Eastern' ->>> amsterdam = timezone('Europe/Amsterdam') ->>> fmt = '%Y-%m-%d %H:%M:%S %Z%z' - -This library only supports two ways of building a localized time. The -first is to use the ``localize()`` method provided by the pytz library. -This is used to localize a naive datetime (datetime with no timezone -information): - ->>> loc_dt = eastern.localize(datetime(2002, 10, 27, 6, 0, 0)) ->>> print(loc_dt.strftime(fmt)) -2002-10-27 06:00:00 EST-0500 - -The second way of building a localized time is by converting an existing -localized time using the standard ``astimezone()`` method: - ->>> ams_dt = loc_dt.astimezone(amsterdam) ->>> ams_dt.strftime(fmt) -'2002-10-27 12:00:00 CET+0100' - -Unfortunately using the tzinfo argument of the standard datetime -constructors ''does not work'' with pytz for many timezones. - ->>> datetime(2002, 10, 27, 12, 0, 0, tzinfo=amsterdam).strftime(fmt) # /!\ Does not work this way! -'2002-10-27 12:00:00 LMT+0020' - -It is safe for timezones without daylight saving transitions though, such -as UTC: - ->>> datetime(2002, 10, 27, 12, 0, 0, tzinfo=pytz.utc).strftime(fmt) # /!\ Not recommended except for UTC -'2002-10-27 12:00:00 UTC+0000' - -The preferred way of dealing with times is to always work in UTC, -converting to localtime only when generating output to be read -by humans. - ->>> utc_dt = datetime(2002, 10, 27, 6, 0, 0, tzinfo=utc) ->>> loc_dt = utc_dt.astimezone(eastern) ->>> loc_dt.strftime(fmt) -'2002-10-27 01:00:00 EST-0500' - -This library also allows you to do date arithmetic using local -times, although it is more complicated than working in UTC as you -need to use the ``normalize()`` method to handle daylight saving time -and other timezone transitions. In this example, ``loc_dt`` is set -to the instant when daylight saving time ends in the US/Eastern -timezone. - ->>> before = loc_dt - timedelta(minutes=10) ->>> before.strftime(fmt) -'2002-10-27 00:50:00 EST-0500' ->>> eastern.normalize(before).strftime(fmt) -'2002-10-27 01:50:00 EDT-0400' ->>> after = eastern.normalize(before + timedelta(minutes=20)) ->>> after.strftime(fmt) -'2002-10-27 01:10:00 EST-0500' - -Creating local times is also tricky, and the reason why working with -local times is not recommended. Unfortunately, you cannot just pass -a ``tzinfo`` argument when constructing a datetime (see the next -section for more details) - ->>> dt = datetime(2002, 10, 27, 1, 30, 0) ->>> dt1 = eastern.localize(dt, is_dst=True) ->>> dt1.strftime(fmt) -'2002-10-27 01:30:00 EDT-0400' ->>> dt2 = eastern.localize(dt, is_dst=False) ->>> dt2.strftime(fmt) -'2002-10-27 01:30:00 EST-0500' - -Converting between timezones is more easily done, using the -standard astimezone method. - ->>> utc_dt = utc.localize(datetime.utcfromtimestamp(1143408899)) ->>> utc_dt.strftime(fmt) -'2006-03-26 21:34:59 UTC+0000' ->>> au_tz = timezone('Australia/Sydney') ->>> au_dt = utc_dt.astimezone(au_tz) ->>> au_dt.strftime(fmt) -'2006-03-27 08:34:59 AEDT+1100' ->>> utc_dt2 = au_dt.astimezone(utc) ->>> utc_dt2.strftime(fmt) -'2006-03-26 21:34:59 UTC+0000' ->>> utc_dt == utc_dt2 -True - -You can take shortcuts when dealing with the UTC side of timezone -conversions. ``normalize()`` and ``localize()`` are not really -necessary when there are no daylight saving time transitions to -deal with. - ->>> utc_dt = datetime.utcfromtimestamp(1143408899).replace(tzinfo=utc) ->>> utc_dt.strftime(fmt) -'2006-03-26 21:34:59 UTC+0000' ->>> au_tz = timezone('Australia/Sydney') ->>> au_dt = au_tz.normalize(utc_dt.astimezone(au_tz)) ->>> au_dt.strftime(fmt) -'2006-03-27 08:34:59 AEDT+1100' ->>> utc_dt2 = au_dt.astimezone(utc) ->>> utc_dt2.strftime(fmt) -'2006-03-26 21:34:59 UTC+0000' - - -``tzinfo`` API --------------- - -The ``tzinfo`` instances returned by the ``timezone()`` function have -been extended to cope with ambiguous times by adding an ``is_dst`` -parameter to the ``utcoffset()``, ``dst()`` && ``tzname()`` methods. - ->>> tz = timezone('America/St_Johns') - ->>> normal = datetime(2009, 9, 1) ->>> ambiguous = datetime(2009, 10, 31, 23, 30) - -The ``is_dst`` parameter is ignored for most timestamps. It is only used -during DST transition ambiguous periods to resolve that ambiguity. - ->>> tz.utcoffset(normal, is_dst=True) -datetime.timedelta(-1, 77400) ->>> tz.dst(normal, is_dst=True) -datetime.timedelta(0, 3600) ->>> tz.tzname(normal, is_dst=True) -'NDT' - ->>> tz.utcoffset(ambiguous, is_dst=True) -datetime.timedelta(-1, 77400) ->>> tz.dst(ambiguous, is_dst=True) -datetime.timedelta(0, 3600) ->>> tz.tzname(ambiguous, is_dst=True) -'NDT' - ->>> tz.utcoffset(normal, is_dst=False) -datetime.timedelta(-1, 77400) ->>> tz.dst(normal, is_dst=False) -datetime.timedelta(0, 3600) ->>> tz.tzname(normal, is_dst=False) -'NDT' - ->>> tz.utcoffset(ambiguous, is_dst=False) -datetime.timedelta(-1, 73800) ->>> tz.dst(ambiguous, is_dst=False) -datetime.timedelta(0) ->>> tz.tzname(ambiguous, is_dst=False) -'NST' - -If ``is_dst`` is not specified, ambiguous timestamps will raise -an ``pytz.exceptions.AmbiguousTimeError`` exception. - ->>> tz.utcoffset(normal) -datetime.timedelta(-1, 77400) ->>> tz.dst(normal) -datetime.timedelta(0, 3600) ->>> tz.tzname(normal) -'NDT' - ->>> import pytz.exceptions ->>> try: -... tz.utcoffset(ambiguous) -... except pytz.exceptions.AmbiguousTimeError: -... print('pytz.exceptions.AmbiguousTimeError: %s' % ambiguous) -pytz.exceptions.AmbiguousTimeError: 2009-10-31 23:30:00 ->>> try: -... tz.dst(ambiguous) -... except pytz.exceptions.AmbiguousTimeError: -... print('pytz.exceptions.AmbiguousTimeError: %s' % ambiguous) -pytz.exceptions.AmbiguousTimeError: 2009-10-31 23:30:00 ->>> try: -... tz.tzname(ambiguous) -... except pytz.exceptions.AmbiguousTimeError: -... print('pytz.exceptions.AmbiguousTimeError: %s' % ambiguous) -pytz.exceptions.AmbiguousTimeError: 2009-10-31 23:30:00 - - -Problems with Localtime -~~~~~~~~~~~~~~~~~~~~~~~ - -The major problem we have to deal with is that certain datetimes -may occur twice in a year. For example, in the US/Eastern timezone -on the last Sunday morning in October, the following sequence -happens: - - - 01:00 EDT occurs - - 1 hour later, instead of 2:00am the clock is turned back 1 hour - and 01:00 happens again (this time 01:00 EST) - -In fact, every instant between 01:00 and 02:00 occurs twice. This means -that if you try and create a time in the 'US/Eastern' timezone -the standard datetime syntax, there is no way to specify if you meant -before of after the end-of-daylight-saving-time transition. Using the -pytz custom syntax, the best you can do is make an educated guess: - ->>> loc_dt = eastern.localize(datetime(2002, 10, 27, 1, 30, 00)) ->>> loc_dt.strftime(fmt) -'2002-10-27 01:30:00 EST-0500' - -As you can see, the system has chosen one for you and there is a 50% -chance of it being out by one hour. For some applications, this does -not matter. However, if you are trying to schedule meetings with people -in different timezones or analyze log files it is not acceptable. - -The best and simplest solution is to stick with using UTC. The pytz -package encourages using UTC for internal timezone representation by -including a special UTC implementation based on the standard Python -reference implementation in the Python documentation. - -The UTC timezone unpickles to be the same instance, and pickles to a -smaller size than other pytz tzinfo instances. The UTC implementation -can be obtained as pytz.utc, pytz.UTC, or pytz.timezone('UTC'). - ->>> import pickle, pytz ->>> dt = datetime(2005, 3, 1, 14, 13, 21, tzinfo=utc) ->>> naive = dt.replace(tzinfo=None) ->>> p = pickle.dumps(dt, 1) ->>> naive_p = pickle.dumps(naive, 1) ->>> len(p) - len(naive_p) -17 ->>> new = pickle.loads(p) ->>> new == dt -True ->>> new is dt -False ->>> new.tzinfo is dt.tzinfo -True ->>> pytz.utc is pytz.UTC is pytz.timezone('UTC') -True - -Note that some other timezones are commonly thought of as the same (GMT, -Greenwich, Universal, etc.). The definition of UTC is distinct from these -other timezones, and they are not equivalent. For this reason, they will -not compare the same in Python. - ->>> utc == pytz.timezone('GMT') -False - -See the section `What is UTC`_, below. - -If you insist on working with local times, this library provides a -facility for constructing them unambiguously: - ->>> loc_dt = datetime(2002, 10, 27, 1, 30, 00) ->>> est_dt = eastern.localize(loc_dt, is_dst=True) ->>> edt_dt = eastern.localize(loc_dt, is_dst=False) ->>> print(est_dt.strftime(fmt) + ' / ' + edt_dt.strftime(fmt)) -2002-10-27 01:30:00 EDT-0400 / 2002-10-27 01:30:00 EST-0500 - -If you pass None as the is_dst flag to localize(), pytz will refuse to -guess and raise exceptions if you try to build ambiguous or non-existent -times. - -For example, 1:30am on 27th Oct 2002 happened twice in the US/Eastern -timezone when the clocks where put back at the end of Daylight Saving -Time: - ->>> dt = datetime(2002, 10, 27, 1, 30, 00) ->>> try: -... eastern.localize(dt, is_dst=None) -... except pytz.exceptions.AmbiguousTimeError: -... print('pytz.exceptions.AmbiguousTimeError: %s' % dt) -pytz.exceptions.AmbiguousTimeError: 2002-10-27 01:30:00 - -Similarly, 2:30am on 7th April 2002 never happened at all in the -US/Eastern timezone, as the clocks where put forward at 2:00am skipping -the entire hour: - ->>> dt = datetime(2002, 4, 7, 2, 30, 00) ->>> try: -... eastern.localize(dt, is_dst=None) -... except pytz.exceptions.NonExistentTimeError: -... print('pytz.exceptions.NonExistentTimeError: %s' % dt) -pytz.exceptions.NonExistentTimeError: 2002-04-07 02:30:00 - -Both of these exceptions share a common base class to make error handling -easier: - ->>> isinstance(pytz.AmbiguousTimeError(), pytz.InvalidTimeError) -True ->>> isinstance(pytz.NonExistentTimeError(), pytz.InvalidTimeError) -True - - -A special case is where countries change their timezone definitions -with no daylight savings time switch. For example, in 1915 Warsaw -switched from Warsaw time to Central European time with no daylight savings -transition. So at the stroke of midnight on August 5th 1915 the clocks -were wound back 24 minutes creating an ambiguous time period that cannot -be specified without referring to the timezone abbreviation or the -actual UTC offset. In this case midnight happened twice, neither time -during a daylight saving time period. pytz handles this transition by -treating the ambiguous period before the switch as daylight savings -time, and the ambiguous period after as standard time. - - ->>> warsaw = pytz.timezone('Europe/Warsaw') ->>> amb_dt1 = warsaw.localize(datetime(1915, 8, 4, 23, 59, 59), is_dst=True) ->>> amb_dt1.strftime(fmt) -'1915-08-04 23:59:59 WMT+0124' ->>> amb_dt2 = warsaw.localize(datetime(1915, 8, 4, 23, 59, 59), is_dst=False) ->>> amb_dt2.strftime(fmt) -'1915-08-04 23:59:59 CET+0100' ->>> switch_dt = warsaw.localize(datetime(1915, 8, 5, 00, 00, 00), is_dst=False) ->>> switch_dt.strftime(fmt) -'1915-08-05 00:00:00 CET+0100' ->>> str(switch_dt - amb_dt1) -'0:24:01' ->>> str(switch_dt - amb_dt2) -'0:00:01' - -The best way of creating a time during an ambiguous time period is -by converting from another timezone such as UTC: - ->>> utc_dt = datetime(1915, 8, 4, 22, 36, tzinfo=pytz.utc) ->>> utc_dt.astimezone(warsaw).strftime(fmt) -'1915-08-04 23:36:00 CET+0100' - -The standard Python way of handling all these ambiguities is not to -handle them, such as demonstrated in this example using the US/Eastern -timezone definition from the Python documentation (Note that this -implementation only works for dates between 1987 and 2006 - it is -included for tests only!): - ->>> from pytz.reference import Eastern # pytz.reference only for tests ->>> dt = datetime(2002, 10, 27, 0, 30, tzinfo=Eastern) ->>> str(dt) -'2002-10-27 00:30:00-04:00' ->>> str(dt + timedelta(hours=1)) -'2002-10-27 01:30:00-05:00' ->>> str(dt + timedelta(hours=2)) -'2002-10-27 02:30:00-05:00' ->>> str(dt + timedelta(hours=3)) -'2002-10-27 03:30:00-05:00' - -Notice the first two results? At first glance you might think they are -correct, but taking the UTC offset into account you find that they are -actually two hours appart instead of the 1 hour we asked for. - ->>> from pytz.reference import UTC # pytz.reference only for tests ->>> str(dt.astimezone(UTC)) -'2002-10-27 04:30:00+00:00' ->>> str((dt + timedelta(hours=1)).astimezone(UTC)) -'2002-10-27 06:30:00+00:00' - - -Country Information -~~~~~~~~~~~~~~~~~~~ - -A mechanism is provided to access the timezones commonly in use -for a particular country, looked up using the ISO 3166 country code. -It returns a list of strings that can be used to retrieve the relevant -tzinfo instance using ``pytz.timezone()``: - ->>> print(' '.join(pytz.country_timezones['nz'])) -Pacific/Auckland Pacific/Chatham - -The Olson database comes with a ISO 3166 country code to English country -name mapping that pytz exposes as a dictionary: - ->>> print(pytz.country_names['nz']) -New Zealand - - -What is UTC -~~~~~~~~~~~ - -'UTC' is `Coordinated Universal Time`_. It is a successor to, but distinct -from, Greenwich Mean Time (GMT) and the various definitions of Universal -Time. UTC is now the worldwide standard for regulating clocks and time -measurement. - -All other timezones are defined relative to UTC, and include offsets like -UTC+0800 - hours to add or subtract from UTC to derive the local time. No -daylight saving time occurs in UTC, making it a useful timezone to perform -date arithmetic without worrying about the confusion and ambiguities caused -by daylight saving time transitions, your country changing its timezone, or -mobile computers that roam through multiple timezones. - -.. _Coordinated Universal Time: https://en.wikipedia.org/wiki/Coordinated_Universal_Time - - -Helpers -~~~~~~~ - -There are two lists of timezones provided. - -``all_timezones`` is the exhaustive list of the timezone names that can -be used. - ->>> from pytz import all_timezones ->>> len(all_timezones) >= 500 -True ->>> 'Etc/Greenwich' in all_timezones -True - -``common_timezones`` is a list of useful, current timezones. It doesn't -contain deprecated zones or historical zones, except for a few I've -deemed in common usage, such as US/Eastern (open a bug report if you -think other timezones are deserving of being included here). It is also -a sequence of strings. - ->>> from pytz import common_timezones ->>> len(common_timezones) < len(all_timezones) -True ->>> 'Etc/Greenwich' in common_timezones -False ->>> 'Australia/Melbourne' in common_timezones -True ->>> 'US/Eastern' in common_timezones -True ->>> 'Canada/Eastern' in common_timezones -True ->>> 'Australia/Yancowinna' in all_timezones -True ->>> 'Australia/Yancowinna' in common_timezones -False - -Both ``common_timezones`` and ``all_timezones`` are alphabetically -sorted: - ->>> common_timezones_dupe = common_timezones[:] ->>> common_timezones_dupe.sort() ->>> common_timezones == common_timezones_dupe -True ->>> all_timezones_dupe = all_timezones[:] ->>> all_timezones_dupe.sort() ->>> all_timezones == all_timezones_dupe -True - -``all_timezones`` and ``common_timezones`` are also available as sets. - ->>> from pytz import all_timezones_set, common_timezones_set ->>> 'US/Eastern' in all_timezones_set -True ->>> 'US/Eastern' in common_timezones_set -True ->>> 'Australia/Victoria' in common_timezones_set -False - -You can also retrieve lists of timezones used by particular countries -using the ``country_timezones()`` function. It requires an ISO-3166 -two letter country code. - ->>> from pytz import country_timezones ->>> print(' '.join(country_timezones('ch'))) -Europe/Zurich ->>> print(' '.join(country_timezones('CH'))) -Europe/Zurich - - -Internationalization - i18n/l10n -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Pytz is an interface to the IANA database, which uses ASCII names. The `Unicode Consortium's Unicode Locales (CLDR) `_ -project provides translations. Thomas Khyn's -`l18n `_ package can be used to access -these translations from Python. - - -License -~~~~~~~ - -MIT license. - -This code is also available as part of Zope 3 under the Zope Public -License, Version 2.1 (ZPL). - -I'm happy to relicense this code if necessary for inclusion in other -open source projects. - - -Latest Versions -~~~~~~~~~~~~~~~ - -This package will be updated after releases of the Olson timezone -database. The latest version can be downloaded from the `Python Package -Index `_. The code that is used -to generate this distribution is hosted on launchpad.net and available -using git:: - - git clone https://git.launchpad.net/pytz - -A mirror on github is also available at https://github.com/stub42/pytz - -Announcements of new releases are made on -`Launchpad `_, and the -`Atom feed `_ -hosted there. - - -Bugs, Feature Requests & Patches -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Bugs can be reported using `Launchpad `__. - - -Issues & Limitations -~~~~~~~~~~~~~~~~~~~~ - -- Offsets from UTC are rounded to the nearest whole minute, so timezones - such as Europe/Amsterdam pre 1937 will be up to 30 seconds out. This - is a limitation of the Python datetime library. - -- If you think a timezone definition is incorrect, I probably can't fix - it. pytz is a direct translation of the Olson timezone database, and - changes to the timezone definitions need to be made to this source. - If you find errors they should be reported to the time zone mailing - list, linked from http://www.iana.org/time-zones. - - -Further Reading -~~~~~~~~~~~~~~~ - -More info than you want to know about timezones: -http://www.twinsun.com/tz/tz-link.htm - - -Contact -~~~~~~~ - -Stuart Bishop - - diff --git a/lib/pytz/__init__.py b/lib/pytz/__init__.py index 34864bea..ccbdfc4e 100644 --- a/lib/pytz/__init__.py +++ b/lib/pytz/__init__.py @@ -16,14 +16,14 @@ from pytz.exceptions import AmbiguousTimeError from pytz.exceptions import InvalidTimeError from pytz.exceptions import NonExistentTimeError from pytz.exceptions import UnknownTimeZoneError -from pytz.lazy import LazyDict, LazyList, LazySet +from pytz.lazy import LazyDict, LazyList, LazySet # noqa from pytz.tzinfo import unpickler, BaseTzInfo from pytz.tzfile import build_tzinfo # The IANA (nee Olson) database is updated several times a year. -OLSON_VERSION = '2018f' -VERSION = '2018.6' # pip compatible version number. +OLSON_VERSION = '2019a' +VERSION = '2019.1' # pip compatible version number. __version__ = VERSION OLSEN_VERSION = OLSON_VERSION # Old releases had this misspelling @@ -157,6 +157,9 @@ def timezone(zone): Unknown ''' + if zone is None: + raise UnknownTimeZoneError(None) + if zone.upper() == 'UTC': return utc @@ -166,9 +169,9 @@ def timezone(zone): # All valid timezones are ASCII raise UnknownTimeZoneError(zone) - zone = _unmunge_zone(zone) + zone = _case_insensitive_zone_lookup(_unmunge_zone(zone)) if zone not in _tzinfo_cache: - if zone in all_timezones_set: + if zone in all_timezones_set: # noqa fp = open_resource(zone) try: _tzinfo_cache[zone] = build_tzinfo(zone, fp) @@ -185,6 +188,11 @@ def _unmunge_zone(zone): return zone.replace('_plus_', '+').replace('_minus_', '-') +def _case_insensitive_zone_lookup(zone): + """case-insensitively matching timezone, else return zone unchanged""" + return _all_timezones_lower_to_standard.get(zone.lower()) or zone # noqa + + ZERO = datetime.timedelta(0) HOUR = datetime.timedelta(hours=1) @@ -272,6 +280,8 @@ def _UTC(): False """ return utc + + _UTC.__safe_for_unpickling__ = True @@ -282,6 +292,8 @@ def _p(*args): by shortening the path. """ return unpickler(*args) + + _p.__safe_for_unpickling__ = True @@ -330,7 +342,7 @@ class _CountryTimezoneDict(LazyDict): if line.startswith('#'): continue code, coordinates, zone = line.split(None, 4)[:3] - if zone not in all_timezones_set: + if zone not in all_timezones_set: # noqa continue try: data[code].append(zone) @@ -340,6 +352,7 @@ class _CountryTimezoneDict(LazyDict): finally: zone_tab.close() + country_timezones = _CountryTimezoneDict() @@ -363,6 +376,7 @@ class _CountryNameDict(LazyDict): finally: zone_tab.close() + country_names = _CountryNameDict() @@ -474,6 +488,7 @@ def FixedOffset(offset, _tzinfos={}): return info + FixedOffset.__safe_for_unpickling__ = True @@ -483,6 +498,7 @@ def _test(): import pytz return doctest.testmod(pytz) + if __name__ == '__main__': _test() all_timezones = \ @@ -787,6 +803,7 @@ all_timezones = \ 'Asia/Pontianak', 'Asia/Pyongyang', 'Asia/Qatar', + 'Asia/Qostanay', 'Asia/Qyzylorda', 'Asia/Rangoon', 'Asia/Riyadh', @@ -1081,6 +1098,7 @@ all_timezones = LazyList( tz for tz in all_timezones if resource_exists(tz)) all_timezones_set = LazySet(all_timezones) +_all_timezones_lower_to_standard = dict((tz.lower(), tz) for tz in all_timezones) common_timezones = \ ['Africa/Abidjan', 'Africa/Accra', @@ -1351,6 +1369,7 @@ common_timezones = \ 'Asia/Pontianak', 'Asia/Pyongyang', 'Asia/Qatar', + 'Asia/Qostanay', 'Asia/Qyzylorda', 'Asia/Riyadh', 'Asia/Sakhalin', diff --git a/lib/pytz/tests/test_docs.py b/lib/pytz/tests/test_docs.py new file mode 100644 index 00000000..c4ed4a3d --- /dev/null +++ b/lib/pytz/tests/test_docs.py @@ -0,0 +1,34 @@ +# -*- coding: ascii -*- + +from doctest import DocFileSuite +import unittest +import os.path +import sys + +THIS_DIR = os.path.dirname(__file__) + +README = os.path.join(THIS_DIR, os.pardir, os.pardir, 'README.txt') + + +class DocumentationTestCase(unittest.TestCase): + def test_readme_encoding(self): + '''Confirm the README.txt is pure ASCII.''' + f = open(README, 'rb') + try: + f.read().decode('ASCII') + finally: + f.close() + + +def test_suite(): + "For the Z3 test runner" + return unittest.TestSuite(( + DocumentationTestCase('test_readme_encoding'), + DocFileSuite(os.path.join(os.pardir, os.pardir, 'README.txt')))) + + +if __name__ == '__main__': + sys.path.insert( + 0, os.path.abspath(os.path.join(THIS_DIR, os.pardir, os.pardir)) + ) + unittest.main(defaultTest='test_suite') diff --git a/lib/pytz/tests/test_lazy.py b/lib/pytz/tests/test_lazy.py new file mode 100644 index 00000000..37097033 --- /dev/null +++ b/lib/pytz/tests/test_lazy.py @@ -0,0 +1,315 @@ +from operator import ( + eq, ge, gt, le, lt, ne, add, concat, not_, sub, and_, or_, xor +) +import os.path +import sys +import unittest +import warnings + + +if __name__ == '__main__': + # Only munge path if invoked as a script. Testrunners should have setup + # the paths already + sys.path.insert(0, os.path.abspath(os.path.join(os.pardir, os.pardir))) + + +from pytz.lazy import LazyList, LazySet + + +class LazyListTestCase(unittest.TestCase): + initial_data = [3, 2, 1] + + def setUp(self): + self.base = [3, 2, 1] + self.lesser = [2, 1, 0] + self.greater = [4, 3, 2] + + self.lazy = LazyList(iter(list(self.base))) + + def test_unary_ops(self): + unary_ops = [str, repr, len, bool, not_] + try: + unary_ops.append(unicode) + except NameError: + pass # unicode no longer exists in Python 3. + + for op in unary_ops: + self.assertEqual( + op(self.lazy), + op(self.base), str(op)) + + def test_binary_ops(self): + binary_ops = [eq, ge, gt, le, lt, ne, add, concat] + try: + binary_ops.append(cmp) + except NameError: + pass # cmp no longer exists in Python 3. + + for op in binary_ops: + self.assertEqual( + op(self.lazy, self.lazy), + op(self.base, self.base), str(op)) + for other in [self.base, self.lesser, self.greater]: + self.assertEqual( + op(self.lazy, other), + op(self.base, other), '%s %s' % (op, other)) + self.assertEqual( + op(other, self.lazy), + op(other, self.base), '%s %s' % (op, other)) + + # Multiplication + self.assertEqual(self.lazy * 3, self.base * 3) + self.assertEqual(3 * self.lazy, 3 * self.base) + + # Contains + self.assertTrue(2 in self.lazy) + self.assertFalse(42 in self.lazy) + + def test_iadd(self): + self.lazy += [1] + self.base += [1] + self.assertEqual(self.lazy, self.base) + + def test_bool(self): + self.assertTrue(bool(self.lazy)) + self.assertFalse(bool(LazyList())) + self.assertFalse(bool(LazyList(iter([])))) + + def test_hash(self): + self.assertRaises(TypeError, hash, self.lazy) + + def test_isinstance(self): + self.assertTrue(isinstance(self.lazy, list)) + self.assertFalse(isinstance(self.lazy, tuple)) + + def test_callable(self): + try: + callable + except NameError: + return # No longer exists with Python 3. + self.assertFalse(callable(self.lazy)) + + def test_append(self): + self.base.append('extra') + self.lazy.append('extra') + self.assertEqual(self.lazy, self.base) + + def test_count(self): + self.assertEqual(self.lazy.count(2), 1) + + def test_index(self): + self.assertEqual(self.lazy.index(2), 1) + + def test_extend(self): + self.base.extend([6, 7]) + self.lazy.extend([6, 7]) + self.assertEqual(self.lazy, self.base) + + def test_insert(self): + self.base.insert(0, 'ping') + self.lazy.insert(0, 'ping') + self.assertEqual(self.lazy, self.base) + + def test_pop(self): + self.assertEqual(self.lazy.pop(), self.base.pop()) + self.assertEqual(self.lazy, self.base) + + def test_remove(self): + self.base.remove(2) + self.lazy.remove(2) + self.assertEqual(self.lazy, self.base) + + def test_reverse(self): + self.base.reverse() + self.lazy.reverse() + self.assertEqual(self.lazy, self.base) + + def test_reversed(self): + self.assertEqual(list(reversed(self.lazy)), list(reversed(self.base))) + + def test_sort(self): + self.base.sort() + self.assertNotEqual(self.lazy, self.base, 'Test data already sorted') + self.lazy.sort() + self.assertEqual(self.lazy, self.base) + + def test_sorted(self): + self.assertEqual(sorted(self.lazy), sorted(self.base)) + + def test_getitem(self): + for idx in range(-len(self.base), len(self.base)): + self.assertEqual(self.lazy[idx], self.base[idx]) + + def test_setitem(self): + for idx in range(-len(self.base), len(self.base)): + self.base[idx] = idx + 1000 + self.assertNotEqual(self.lazy, self.base) + self.lazy[idx] = idx + 1000 + self.assertEqual(self.lazy, self.base) + + def test_delitem(self): + del self.base[0] + self.assertNotEqual(self.lazy, self.base) + del self.lazy[0] + self.assertEqual(self.lazy, self.base) + + del self.base[-2] + self.assertNotEqual(self.lazy, self.base) + del self.lazy[-2] + self.assertEqual(self.lazy, self.base) + + def test_iter(self): + self.assertEqual(list(iter(self.lazy)), list(iter(self.base))) + + def test_getslice(self): + for i in range(-len(self.base), len(self.base)): + for j in range(-len(self.base), len(self.base)): + for step in [-1, 1]: + self.assertEqual(self.lazy[i:j:step], self.base[i:j:step]) + + def test_setslice(self): + for i in range(-len(self.base), len(self.base)): + for j in range(-len(self.base), len(self.base)): + for step in [-1, 1]: + replacement = range(0, len(self.base[i:j:step])) + self.base[i:j:step] = replacement + self.lazy[i:j:step] = replacement + self.assertEqual(self.lazy, self.base) + + def test_delslice(self): + del self.base[0:1] + del self.lazy[0:1] + self.assertEqual(self.lazy, self.base) + + del self.base[-1:1:-1] + del self.lazy[-1:1:-1] + self.assertEqual(self.lazy, self.base) + + +class LazySetTestCase(unittest.TestCase): + initial_data = set([3, 2, 1]) + + def setUp(self): + self.base = set([3, 2, 1]) + self.lazy = LazySet(iter(set(self.base))) + + def test_unary_ops(self): + # These ops just need to work. + unary_ops = [str, repr] + try: + unary_ops.append(unicode) + except NameError: + pass # unicode no longer exists in Python 3. + + for op in unary_ops: + op(self.lazy) # These ops just need to work. + + # These ops should return identical values as a real set. + unary_ops = [len, bool, not_] + + for op in unary_ops: + self.assertEqual( + op(self.lazy), + op(self.base), '%s(lazy) == %r' % (op, op(self.lazy))) + + def test_binary_ops(self): + binary_ops = [eq, ge, gt, le, lt, ne, sub, and_, or_, xor] + try: + binary_ops.append(cmp) + except NameError: + pass # cmp no longer exists in Python 3. + + for op in binary_ops: + self.assertEqual( + op(self.lazy, self.lazy), + op(self.base, self.base), str(op)) + self.assertEqual( + op(self.lazy, self.base), + op(self.base, self.base), str(op)) + self.assertEqual( + op(self.base, self.lazy), + op(self.base, self.base), str(op)) + + # Contains + self.assertTrue(2 in self.lazy) + self.assertFalse(42 in self.lazy) + + def test_iops(self): + try: + iops = [isub, iand, ior, ixor] + except NameError: + return # Don't exist in older Python versions. + for op in iops: + # Mutating operators, so make fresh copies. + lazy = LazySet(self.base) + base = self.base.copy() + op(lazy, set([1])) + op(base, set([1])) + self.assertEqual(lazy, base, str(op)) + + def test_bool(self): + self.assertTrue(bool(self.lazy)) + self.assertFalse(bool(LazySet())) + self.assertFalse(bool(LazySet(iter([])))) + + def test_hash(self): + self.assertRaises(TypeError, hash, self.lazy) + + def test_isinstance(self): + self.assertTrue(isinstance(self.lazy, set)) + + def test_callable(self): + try: + callable + except NameError: + return # No longer exists with Python 3. + self.assertFalse(callable(self.lazy)) + + def test_add(self): + self.base.add('extra') + self.lazy.add('extra') + self.assertEqual(self.lazy, self.base) + + def test_copy(self): + self.assertEqual(self.lazy.copy(), self.base) + + def test_method_ops(self): + ops = [ + 'difference', 'intersection', 'isdisjoint', + 'issubset', 'issuperset', 'symmetric_difference', 'union', + 'difference_update', 'intersection_update', + 'symmetric_difference_update', 'update'] + for op in ops: + if not hasattr(set, op): + continue # Not in this version of Python. + # Make a copy, as some of the ops are mutating. + lazy = LazySet(set(self.base)) + base = set(self.base) + self.assertEqual( + getattr(lazy, op)(set([1])), + getattr(base, op)(set([1])), op) + self.assertEqual(lazy, base, op) + + def test_discard(self): + self.base.discard(1) + self.assertNotEqual(self.lazy, self.base) + self.lazy.discard(1) + self.assertEqual(self.lazy, self.base) + + def test_pop(self): + self.assertEqual(self.lazy.pop(), self.base.pop()) + self.assertEqual(self.lazy, self.base) + + def test_remove(self): + self.base.remove(2) + self.lazy.remove(2) + self.assertEqual(self.lazy, self.base) + + def test_clear(self): + self.lazy.clear() + self.assertEqual(self.lazy, set()) + + +if __name__ == '__main__': + warnings.simplefilter("error") # Warnings should be fatal in tests. + unittest.main() diff --git a/lib/pytz/tests/test_tzinfo.py b/lib/pytz/tests/test_tzinfo.py new file mode 100644 index 00000000..e56fef53 --- /dev/null +++ b/lib/pytz/tests/test_tzinfo.py @@ -0,0 +1,863 @@ +# -*- coding: ascii -*- + +import doctest +import sys +import os +import os.path +import unittest +try: + import cPickle as pickle +except ImportError: + import pickle +from datetime import ( + datetime, + timedelta +) +import warnings + +if __name__ == '__main__': + # Only munge path if invoked as a script. Testrunners should have setup + # the paths already + sys.path.insert(0, os.path.abspath(os.path.join(os.pardir, os.pardir))) + +import pytz # noqa +from pytz import reference # noqa +from pytz.tzfile import _byte_string # noqa +from pytz.tzinfo import DstTzInfo, StaticTzInfo # noqa + +# I test for expected version to ensure the correct version of pytz is +# actually being tested. +EXPECTED_VERSION = '2019.1' +EXPECTED_OLSON_VERSION = '2019a' + +fmt = '%Y-%m-%d %H:%M:%S %Z%z' + +NOTIME = timedelta(0) + +# GMT is a tzinfo.StaticTzInfo--the class we primarily want to test--while +# UTC is reference implementation. They both have the same timezone meaning. +UTC = pytz.timezone('UTC') +GMT = pytz.timezone('GMT') +assert isinstance(GMT, StaticTzInfo), 'GMT is no longer a StaticTzInfo' + + +def prettydt(dt): + """datetime as a string using a known format. + + We don't use strftime as it doesn't handle years earlier than 1900 + per http://bugs.python.org/issue1777412 + """ + if dt.utcoffset() >= timedelta(0): + offset = '+%s' % (dt.utcoffset(),) + else: + offset = '-%s' % (-1 * dt.utcoffset(),) + return '%04d-%02d-%02d %02d:%02d:%02d %s %s' % ( + dt.year, dt.month, dt.day, + dt.hour, dt.minute, dt.second, + dt.tzname(), offset) + + +if sys.version_info[0] > 2: + # Python 3.x doesn't have unicode(), making writing code + # for Python 2.3 and Python 3.x a pain. + unicode = str + + +class BasicTest(unittest.TestCase): + + def testVersion(self): + # Ensuring the correct version of pytz has been loaded + self.assertEqual( + EXPECTED_VERSION, pytz.__version__, + 'Incorrect pytz version loaded. Import path is stuffed ' + 'or this test needs updating. (Wanted %s, got %s)' + % (EXPECTED_VERSION, pytz.__version__) + ) + + self.assertEqual( + EXPECTED_OLSON_VERSION, pytz.OLSON_VERSION, + 'Incorrect pytz version loaded. Import path is stuffed ' + 'or this test needs updating. (Wanted %s, got %s)' + % (EXPECTED_OLSON_VERSION, pytz.OLSON_VERSION) + ) + + def testGMT(self): + now = datetime.now(tz=GMT) + self.assertTrue(now.utcoffset() == NOTIME) + self.assertTrue(now.dst() == NOTIME) + self.assertTrue(now.timetuple() == now.utctimetuple()) + self.assertTrue(now == now.replace(tzinfo=UTC)) + + def testReferenceUTC(self): + now = datetime.now(tz=UTC) + self.assertTrue(now.utcoffset() == NOTIME) + self.assertTrue(now.dst() == NOTIME) + self.assertTrue(now.timetuple() == now.utctimetuple()) + + def testUnknownOffsets(self): + # This tzinfo behavior is required to make + # datetime.time.{utcoffset, dst, tzname} work as documented. + + dst_tz = pytz.timezone('US/Eastern') + + # This information is not known when we don't have a date, + # so return None per API. + self.assertTrue(dst_tz.utcoffset(None) is None) + self.assertTrue(dst_tz.dst(None) is None) + # We don't know the abbreviation, but this is still a valid + # tzname per the Python documentation. + self.assertEqual(dst_tz.tzname(None), 'US/Eastern') + + def clearCache(self): + pytz._tzinfo_cache.clear() + + def testUnicodeTimezone(self): + # We need to ensure that cold lookups work for both Unicode + # and traditional strings, and that the desired singleton is + # returned. + self.clearCache() + eastern = pytz.timezone(unicode('US/Eastern')) + self.assertTrue(eastern is pytz.timezone('US/Eastern')) + + self.clearCache() + eastern = pytz.timezone('US/Eastern') + self.assertTrue(eastern is pytz.timezone(unicode('US/Eastern'))) + + def testStaticTzInfo(self): + # Ensure that static timezones are correctly detected, + # per lp:1602807 + static = pytz.timezone('Etc/GMT-4') + self.assertTrue(isinstance(static, StaticTzInfo)) + + +class PicklingTest(unittest.TestCase): + + def _roundtrip_tzinfo(self, tz): + p = pickle.dumps(tz) + unpickled_tz = pickle.loads(p) + self.assertTrue(tz is unpickled_tz, '%s did not roundtrip' % tz.zone) + + def _roundtrip_datetime(self, dt): + # Ensure that the tzinfo attached to a datetime instance + # is identical to the one returned. This is important for + # DST timezones, as some state is stored in the tzinfo. + tz = dt.tzinfo + p = pickle.dumps(dt) + unpickled_dt = pickle.loads(p) + unpickled_tz = unpickled_dt.tzinfo + self.assertTrue(tz is unpickled_tz, '%s did not roundtrip' % tz.zone) + + def testDst(self): + tz = pytz.timezone('Europe/Amsterdam') + dt = datetime(2004, 2, 1, 0, 0, 0) + + for localized_tz in tz._tzinfos.values(): + self._roundtrip_tzinfo(localized_tz) + self._roundtrip_datetime(dt.replace(tzinfo=localized_tz)) + + def testRoundtrip(self): + for zone in pytz.all_timezones: + tz = pytz.timezone(zone) + self._roundtrip_tzinfo(tz) + + def testDatabaseFixes(self): + # Hack the pickle to make it refer to a timezone abbreviation + # that does not match anything. The unpickler should be able + # to repair this case + tz = pytz.timezone('Australia/Melbourne') + p = pickle.dumps(tz) + tzname = tz._tzname + hacked_p = p.replace( + _byte_string(tzname), + _byte_string('?' * len(tzname)) + ) + self.assertNotEqual(p, hacked_p) + unpickled_tz = pickle.loads(hacked_p) + self.assertTrue(tz is unpickled_tz) + + # Simulate a database correction. In this case, the incorrect + # data will continue to be used. + p = pickle.dumps(tz) + new_utcoffset = tz._utcoffset.seconds + 42 + + # Python 3 introduced a new pickle protocol where numbers are stored in + # hexadecimal representation. Here we extract the pickle + # representation of the number for the current Python version. + old_pickle_pattern = pickle.dumps(tz._utcoffset.seconds)[3:-1] + new_pickle_pattern = pickle.dumps(new_utcoffset)[3:-1] + hacked_p = p.replace(old_pickle_pattern, new_pickle_pattern) + + self.assertNotEqual(p, hacked_p) + unpickled_tz = pickle.loads(hacked_p) + self.assertEqual(unpickled_tz._utcoffset.seconds, new_utcoffset) + self.assertTrue(tz is not unpickled_tz) + + def testOldPickles(self): + # Ensure that applications serializing pytz instances as pickles + # have no troubles upgrading to a new pytz release. These pickles + # where created with pytz2006j + east1 = pickle.loads( + _byte_string( + "cpytz\n_p\np1\n(S'US/Eastern'\np2\nI-18000\n" + "I0\nS'EST'\np3\ntRp4\n." + ) + ) + east2 = pytz.timezone('US/Eastern').localize( + datetime(2006, 1, 1)).tzinfo + self.assertTrue(east1 is east2) + + # Confirm changes in name munging between 2006j and 2007c cause + # no problems. + pap1 = pickle.loads(_byte_string( + "cpytz\n_p\np1\n(S'America/Port_minus_au_minus_Prince'" + "\np2\nI-17340\nI0\nS'PPMT'\np3\ntRp4\n.")) + pap2 = pytz.timezone('America/Port-au-Prince').localize( + datetime(1910, 1, 1)).tzinfo + self.assertTrue(pap1 is pap2) + + gmt1 = pickle.loads(_byte_string( + "cpytz\n_p\np1\n(S'Etc/GMT_plus_10'\np2\ntRp3\n.")) + gmt2 = pytz.timezone('Etc/GMT+10') + self.assertTrue(gmt1 is gmt2) + + +class USEasternDSTStartTestCase(unittest.TestCase): + tzinfo = pytz.timezone('US/Eastern') + + # 24 hours before DST changeover + transition_time = datetime(2002, 4, 7, 7, 0, 0, tzinfo=UTC) + + # Increase for 'flexible' DST transitions due to 1 minute granularity + # of Python's datetime library + instant = timedelta(seconds=1) + + # before transition + before = { + 'tzname': 'EST', + 'utcoffset': timedelta(hours=-5), + 'dst': timedelta(hours=0), + } + + # after transition + after = { + 'tzname': 'EDT', + 'utcoffset': timedelta(hours=-4), + 'dst': timedelta(hours=1), + } + + def _test_tzname(self, utc_dt, wanted): + tzname = wanted['tzname'] + dt = utc_dt.astimezone(self.tzinfo) + self.assertEqual( + dt.tzname(), tzname, + 'Expected %s as tzname for %s. Got %s' % ( + tzname, str(utc_dt), dt.tzname() + ) + ) + + def _test_utcoffset(self, utc_dt, wanted): + utcoffset = wanted['utcoffset'] + dt = utc_dt.astimezone(self.tzinfo) + self.assertEqual( + dt.utcoffset(), wanted['utcoffset'], + 'Expected %s as utcoffset for %s. Got %s' % ( + utcoffset, utc_dt, dt.utcoffset() + ) + ) + + def _test_dst(self, utc_dt, wanted): + dst = wanted['dst'] + dt = utc_dt.astimezone(self.tzinfo) + self.assertEqual( + dt.dst(), dst, + 'Expected %s as dst for %s. Got %s' % (dst, utc_dt, dt.dst()) + ) + + def test_arithmetic(self): + utc_dt = self.transition_time + + for days in range(-420, 720, 20): + delta = timedelta(days=days) + + # Make sure we can get back where we started + dt = utc_dt.astimezone(self.tzinfo) + dt2 = dt + delta + dt2 = dt2 - delta + self.assertEqual(dt, dt2) + + # Make sure arithmetic crossing DST boundaries ends + # up in the correct timezone after normalization + utc_plus_delta = (utc_dt + delta).astimezone(self.tzinfo) + local_plus_delta = self.tzinfo.normalize(dt + delta) + self.assertEqual( + prettydt(utc_plus_delta), prettydt(local_plus_delta), + 'Incorrect result for delta==%d days. Wanted %r. Got %r' % ( + days, prettydt(utc_plus_delta), prettydt(local_plus_delta), + ) + ) + + def _test_all(self, utc_dt, wanted): + self._test_utcoffset(utc_dt, wanted) + self._test_tzname(utc_dt, wanted) + self._test_dst(utc_dt, wanted) + + def testDayBefore(self): + self._test_all( + self.transition_time - timedelta(days=1), self.before + ) + + def testTwoHoursBefore(self): + self._test_all( + self.transition_time - timedelta(hours=2), self.before + ) + + def testHourBefore(self): + self._test_all( + self.transition_time - timedelta(hours=1), self.before + ) + + def testInstantBefore(self): + self._test_all( + self.transition_time - self.instant, self.before + ) + + def testTransition(self): + self._test_all( + self.transition_time, self.after + ) + + def testInstantAfter(self): + self._test_all( + self.transition_time + self.instant, self.after + ) + + def testHourAfter(self): + self._test_all( + self.transition_time + timedelta(hours=1), self.after + ) + + def testTwoHoursAfter(self): + self._test_all( + self.transition_time + timedelta(hours=1), self.after + ) + + def testDayAfter(self): + self._test_all( + self.transition_time + timedelta(days=1), self.after + ) + + +class USEasternDSTEndTestCase(USEasternDSTStartTestCase): + tzinfo = pytz.timezone('US/Eastern') + transition_time = datetime(2002, 10, 27, 6, 0, 0, tzinfo=UTC) + before = { + 'tzname': 'EDT', + 'utcoffset': timedelta(hours=-4), + 'dst': timedelta(hours=1), + } + after = { + 'tzname': 'EST', + 'utcoffset': timedelta(hours=-5), + 'dst': timedelta(hours=0), + } + + +class USEasternEPTStartTestCase(USEasternDSTStartTestCase): + transition_time = datetime(1945, 8, 14, 23, 0, 0, tzinfo=UTC) + before = { + 'tzname': 'EWT', + 'utcoffset': timedelta(hours=-4), + 'dst': timedelta(hours=1), + } + after = { + 'tzname': 'EPT', + 'utcoffset': timedelta(hours=-4), + 'dst': timedelta(hours=1), + } + + +class USEasternEPTEndTestCase(USEasternDSTStartTestCase): + transition_time = datetime(1945, 9, 30, 6, 0, 0, tzinfo=UTC) + before = { + 'tzname': 'EPT', + 'utcoffset': timedelta(hours=-4), + 'dst': timedelta(hours=1), + } + after = { + 'tzname': 'EST', + 'utcoffset': timedelta(hours=-5), + 'dst': timedelta(hours=0), + } + + +class WarsawWMTEndTestCase(USEasternDSTStartTestCase): + # In 1915, Warsaw changed from Warsaw to Central European time. + # This involved the clocks being set backwards, causing a end-of-DST + # like situation without DST being involved. + tzinfo = pytz.timezone('Europe/Warsaw') + transition_time = datetime(1915, 8, 4, 22, 36, 0, tzinfo=UTC) + before = { + 'tzname': 'WMT', + 'utcoffset': timedelta(hours=1, minutes=24), + 'dst': timedelta(0), + } + after = { + 'tzname': 'CET', + 'utcoffset': timedelta(hours=1), + 'dst': timedelta(0), + } + + +class VilniusWMTEndTestCase(USEasternDSTStartTestCase): + # At the end of 1916, Vilnius changed timezones putting its clock + # forward by 11 minutes 35 seconds. Neither timezone was in DST mode. + tzinfo = pytz.timezone('Europe/Vilnius') + instant = timedelta(seconds=31) + transition_time = datetime(1916, 12, 31, 22, 36, 00, tzinfo=UTC) + before = { + 'tzname': 'WMT', + 'utcoffset': timedelta(hours=1, minutes=24), + 'dst': timedelta(0), + } + after = { + 'tzname': 'KMT', + 'utcoffset': timedelta(hours=1, minutes=36), # Really 1:35:36 + 'dst': timedelta(0), + } + + +class VilniusCESTStartTestCase(USEasternDSTStartTestCase): + # In 1941, Vilnius changed from MSG to CEST, switching to summer + # time while simultaneously reducing its UTC offset by two hours, + # causing the clocks to go backwards for this summer time + # switchover. + tzinfo = pytz.timezone('Europe/Vilnius') + transition_time = datetime(1941, 6, 23, 21, 00, 00, tzinfo=UTC) + before = { + 'tzname': 'MSK', + 'utcoffset': timedelta(hours=3), + 'dst': timedelta(0), + } + after = { + 'tzname': 'CEST', + 'utcoffset': timedelta(hours=2), + 'dst': timedelta(hours=1), + } + + +class LondonHistoryStartTestCase(USEasternDSTStartTestCase): + # The first known timezone transition in London was in 1847 when + # clocks where synchronized to GMT. However, we currently only + # understand v1 format tzfile(5) files which does handle years + # this far in the past, so our earliest known transition is in + # 1916. + tzinfo = pytz.timezone('Europe/London') + # transition_time = datetime(1847, 12, 1, 1, 15, 00, tzinfo=UTC) + # before = { + # 'tzname': 'LMT', + # 'utcoffset': timedelta(minutes=-75), + # 'dst': timedelta(0), + # } + # after = { + # 'tzname': 'GMT', + # 'utcoffset': timedelta(0), + # 'dst': timedelta(0), + # } + transition_time = datetime(1916, 5, 21, 2, 00, 00, tzinfo=UTC) + before = { + 'tzname': 'GMT', + 'utcoffset': timedelta(0), + 'dst': timedelta(0), + } + after = { + 'tzname': 'BST', + 'utcoffset': timedelta(hours=1), + 'dst': timedelta(hours=1), + } + + +class LondonHistoryEndTestCase(USEasternDSTStartTestCase): + # Timezone switchovers are projected into the future, even + # though no official statements exist or could be believed even + # if they did exist. We currently only check the last known + # transition in 2037, as we are still using v1 format tzfile(5) + # files. + tzinfo = pytz.timezone('Europe/London') + # transition_time = datetime(2499, 10, 25, 1, 0, 0, tzinfo=UTC) + transition_time = datetime(2037, 10, 25, 1, 0, 0, tzinfo=UTC) + before = { + 'tzname': 'BST', + 'utcoffset': timedelta(hours=1), + 'dst': timedelta(hours=1), + } + after = { + 'tzname': 'GMT', + 'utcoffset': timedelta(0), + 'dst': timedelta(0), + } + + +class NoumeaHistoryStartTestCase(USEasternDSTStartTestCase): + # Noumea adopted a whole hour offset in 1912. Previously + # it was 11 hours, 5 minutes and 48 seconds off UTC. However, + # due to limitations of the Python datetime library, we need + # to round that to 11 hours 6 minutes. + tzinfo = pytz.timezone('Pacific/Noumea') + transition_time = datetime(1912, 1, 12, 12, 54, 12, tzinfo=UTC) + before = { + 'tzname': 'LMT', + 'utcoffset': timedelta(hours=11, minutes=6), + 'dst': timedelta(0), + } + after = { + 'tzname': '+11', # pre-2017a, NCT + 'utcoffset': timedelta(hours=11), + 'dst': timedelta(0), + } + + +class NoumeaDSTEndTestCase(USEasternDSTStartTestCase): + # Noumea dropped DST in 1997. + tzinfo = pytz.timezone('Pacific/Noumea') + transition_time = datetime(1997, 3, 1, 15, 00, 00, tzinfo=UTC) + before = { + 'tzname': '+12', # pre-2017a, NCST + 'utcoffset': timedelta(hours=12), + 'dst': timedelta(hours=1), + } + after = { + 'tzname': '+11', # pre-2017a, NCT + 'utcoffset': timedelta(hours=11), + 'dst': timedelta(0), + } + + +class NoumeaNoMoreDSTTestCase(NoumeaDSTEndTestCase): + # Noumea dropped DST in 1997. Here we test that it stops occuring. + transition_time = ( + NoumeaDSTEndTestCase.transition_time + timedelta(days=365 * 10)) + before = NoumeaDSTEndTestCase.after + after = NoumeaDSTEndTestCase.after + + +class TahitiTestCase(USEasternDSTStartTestCase): + # Tahiti has had a single transition in its history. + tzinfo = pytz.timezone('Pacific/Tahiti') + transition_time = datetime(1912, 10, 1, 9, 58, 16, tzinfo=UTC) + before = { + 'tzname': 'LMT', + 'utcoffset': timedelta(hours=-9, minutes=-58), + 'dst': timedelta(0), + } + after = { + 'tzname': '-10', # pre-2017a, TAHT + 'utcoffset': timedelta(hours=-10), + 'dst': timedelta(0), + } + + +class SamoaInternationalDateLineChange(USEasternDSTStartTestCase): + # At the end of 2011, Samoa will switch from being east of the + # international dateline to the west. There will be no Dec 30th + # 2011 and it will switch from UTC-10 to UTC+14. + tzinfo = pytz.timezone('Pacific/Apia') + transition_time = datetime(2011, 12, 30, 10, 0, 0, tzinfo=UTC) + before = { + 'tzname': '-10', # pre-2017a, SDT + 'utcoffset': timedelta(hours=-10), + 'dst': timedelta(hours=1), + } + after = { + 'tzname': '+14', # pre-2017a, WSDT + 'utcoffset': timedelta(hours=14), + 'dst': timedelta(hours=1), + } + + +class ReferenceUSEasternDSTStartTestCase(USEasternDSTStartTestCase): + tzinfo = reference.Eastern + + def test_arithmetic(self): + # Reference implementation cannot handle this + pass + + +class ReferenceUSEasternDSTEndTestCase(USEasternDSTEndTestCase): + tzinfo = reference.Eastern + + def testHourBefore(self): + # Python's datetime library has a bug, where the hour before + # a daylight saving transition is one hour out. For example, + # at the end of US/Eastern daylight saving time, 01:00 EST + # occurs twice (once at 05:00 UTC and once at 06:00 UTC), + # whereas the first should actually be 01:00 EDT. + # Note that this bug is by design - by accepting this ambiguity + # for one hour one hour per year, an is_dst flag on datetime.time + # became unnecessary. + self._test_all(self.transition_time - timedelta(hours=1), self.after) + + def testInstantBefore(self): + self._test_all(self.transition_time - timedelta(seconds=1), self.after) + + def test_arithmetic(self): + # Reference implementation cannot handle this + pass + + +class LocalTestCase(unittest.TestCase): + def testLocalize(self): + loc_tz = pytz.timezone('Europe/Amsterdam') + + loc_time = loc_tz.localize(datetime(1930, 5, 10, 0, 0, 0)) + # Actually +00:19:32, but Python datetime rounds this + self.assertEqual(loc_time.strftime('%Z%z'), 'AMT+0020') + + loc_time = loc_tz.localize(datetime(1930, 5, 20, 0, 0, 0)) + # Actually +00:19:32, but Python datetime rounds this + self.assertEqual(loc_time.strftime('%Z%z'), 'NST+0120') + + loc_time = loc_tz.localize(datetime(1940, 5, 10, 0, 0, 0)) + # pre-2017a, abbreviation was NCT + self.assertEqual(loc_time.strftime('%Z%z'), '+0020+0020') + + loc_time = loc_tz.localize(datetime(1940, 5, 20, 0, 0, 0)) + self.assertEqual(loc_time.strftime('%Z%z'), 'CEST+0200') + + loc_time = loc_tz.localize(datetime(2004, 2, 1, 0, 0, 0)) + self.assertEqual(loc_time.strftime('%Z%z'), 'CET+0100') + + loc_time = loc_tz.localize(datetime(2004, 4, 1, 0, 0, 0)) + self.assertEqual(loc_time.strftime('%Z%z'), 'CEST+0200') + + loc_time = loc_tz.localize(datetime(1943, 3, 29, 1, 59, 59)) + self.assertEqual(loc_time.strftime('%Z%z'), 'CET+0100') + + # Switch to US + loc_tz = pytz.timezone('US/Eastern') + + # End of DST ambiguity check + loc_time = loc_tz.localize(datetime(1918, 10, 27, 1, 59, 59), is_dst=1) + self.assertEqual(loc_time.strftime('%Z%z'), 'EDT-0400') + + loc_time = loc_tz.localize(datetime(1918, 10, 27, 1, 59, 59), is_dst=0) + self.assertEqual(loc_time.strftime('%Z%z'), 'EST-0500') + + self.assertRaises( + pytz.AmbiguousTimeError, + loc_tz.localize, datetime(1918, 10, 27, 1, 59, 59), is_dst=None + ) + + # Start of DST non-existent times + loc_time = loc_tz.localize(datetime(1918, 3, 31, 2, 0, 0), is_dst=0) + self.assertEqual(loc_time.strftime('%Z%z'), 'EST-0500') + + loc_time = loc_tz.localize(datetime(1918, 3, 31, 2, 0, 0), is_dst=1) + self.assertEqual(loc_time.strftime('%Z%z'), 'EDT-0400') + + self.assertRaises( + pytz.NonExistentTimeError, + loc_tz.localize, datetime(1918, 3, 31, 2, 0, 0), is_dst=None + ) + + # Weird changes - war time and peace time both is_dst==True + + loc_time = loc_tz.localize(datetime(1942, 2, 9, 3, 0, 0)) + self.assertEqual(loc_time.strftime('%Z%z'), 'EWT-0400') + + loc_time = loc_tz.localize(datetime(1945, 8, 14, 19, 0, 0)) + self.assertEqual(loc_time.strftime('%Z%z'), 'EPT-0400') + + loc_time = loc_tz.localize(datetime(1945, 9, 30, 1, 0, 0), is_dst=1) + self.assertEqual(loc_time.strftime('%Z%z'), 'EPT-0400') + + loc_time = loc_tz.localize(datetime(1945, 9, 30, 1, 0, 0), is_dst=0) + self.assertEqual(loc_time.strftime('%Z%z'), 'EST-0500') + + # Weird changes - ambiguous time (end-of-DST like) but is_dst==False + for zonename, ambiguous_naive, expected in [ + ('Europe/Warsaw', datetime(1915, 8, 4, 23, 59, 59), + ['1915-08-04 23:59:59 WMT+0124', + '1915-08-04 23:59:59 CET+0100']), + ('Europe/Moscow', datetime(2014, 10, 26, 1, 30), + ['2014-10-26 01:30:00 MSK+0400', + '2014-10-26 01:30:00 MSK+0300'])]: + loc_tz = pytz.timezone(zonename) + self.assertRaises( + pytz.AmbiguousTimeError, + loc_tz.localize, ambiguous_naive, is_dst=None + ) + # Also test non-boolean is_dst in the weird case + for dst in [True, timedelta(1), False, timedelta(0)]: + loc_time = loc_tz.localize(ambiguous_naive, is_dst=dst) + self.assertEqual(loc_time.strftime(fmt), expected[not dst]) + + def testNormalize(self): + tz = pytz.timezone('US/Eastern') + dt = datetime(2004, 4, 4, 7, 0, 0, tzinfo=UTC).astimezone(tz) + dt2 = dt - timedelta(minutes=10) + self.assertEqual( + dt2.strftime('%Y-%m-%d %H:%M:%S %Z%z'), + '2004-04-04 02:50:00 EDT-0400' + ) + + dt2 = tz.normalize(dt2) + self.assertEqual( + dt2.strftime('%Y-%m-%d %H:%M:%S %Z%z'), + '2004-04-04 01:50:00 EST-0500' + ) + + def testPartialMinuteOffsets(self): + # utcoffset in Amsterdam was not a whole minute until 1937 + # However, we fudge this by rounding them, as the Python + # datetime library + tz = pytz.timezone('Europe/Amsterdam') + utc_dt = datetime(1914, 1, 1, 13, 40, 28, tzinfo=UTC) # correct + utc_dt = utc_dt.replace(second=0) # But we need to fudge it + loc_dt = utc_dt.astimezone(tz) + self.assertEqual( + loc_dt.strftime('%Y-%m-%d %H:%M:%S %Z%z'), + '1914-01-01 14:00:00 AMT+0020' + ) + + # And get back... + utc_dt = loc_dt.astimezone(UTC) + self.assertEqual( + utc_dt.strftime('%Y-%m-%d %H:%M:%S %Z%z'), + '1914-01-01 13:40:00 UTC+0000' + ) + + def no_testCreateLocaltime(self): + # It would be nice if this worked, but it doesn't. + tz = pytz.timezone('Europe/Amsterdam') + dt = datetime(2004, 10, 31, 2, 0, 0, tzinfo=tz) + self.assertEqual( + dt.strftime(fmt), + '2004-10-31 02:00:00 CET+0100' + ) + + +class CommonTimezonesTestCase(unittest.TestCase): + def test_bratislava(self): + # Bratislava is the default timezone for Slovakia, but our + # heuristics where not adding it to common_timezones. Ideally, + # common_timezones should be populated from zone.tab at runtime, + # but I'm hesitant to pay the startup cost as loading the list + # on demand whilst remaining backwards compatible seems + # difficult. + self.assertTrue('Europe/Bratislava' in pytz.common_timezones) + self.assertTrue('Europe/Bratislava' in pytz.common_timezones_set) + + def test_us_eastern(self): + self.assertTrue('US/Eastern' in pytz.common_timezones) + self.assertTrue('US/Eastern' in pytz.common_timezones_set) + + def test_belfast(self): + # Belfast uses London time. + self.assertTrue('Europe/Belfast' in pytz.all_timezones_set) + self.assertFalse('Europe/Belfast' in pytz.common_timezones) + self.assertFalse('Europe/Belfast' in pytz.common_timezones_set) + + +class ZoneCaseInsensitivityTestCase(unittest.TestCase): + def test_lower_case_timezone_constructor_arg(self): + for tz in pytz.all_timezones_set: + from_lower = pytz.timezone(tz.lower()) + from_passed = pytz.timezone(tz) + self.assertEqual(from_lower, + from_passed, + "arg '%s' and arg '%s' produce different " + "timezone objects" % ( + from_lower, from_passed)) + + +class BaseTzInfoTestCase: + '''Ensure UTC, StaticTzInfo and DstTzInfo work consistently. + + These tests are run for each type of tzinfo. + ''' + tz = None # override + tz_class = None # override + + def test_expectedclass(self): + self.assertTrue(isinstance(self.tz, self.tz_class)) + + def test_fromutc(self): + # naive datetime. + dt1 = datetime(2011, 10, 31) + + # localized datetime, same timezone. + dt2 = self.tz.localize(dt1) + + # Both should give the same results. Note that the standard + # Python tzinfo.fromutc() only supports the second. + for dt in [dt1, dt2]: + loc_dt = self.tz.fromutc(dt) + loc_dt2 = pytz.utc.localize(dt1).astimezone(self.tz) + self.assertEqual(loc_dt, loc_dt2) + + # localized datetime, different timezone. + new_tz = pytz.timezone('Europe/Paris') + self.assertTrue(self.tz is not new_tz) + dt3 = new_tz.localize(dt1) + self.assertRaises(ValueError, self.tz.fromutc, dt3) + + def test_normalize(self): + other_tz = pytz.timezone('Europe/Paris') + self.assertTrue(self.tz is not other_tz) + + dt = datetime(2012, 3, 26, 12, 0) + other_dt = other_tz.localize(dt) + + local_dt = self.tz.normalize(other_dt) + + self.assertTrue(local_dt.tzinfo is not other_dt.tzinfo) + self.assertNotEqual( + local_dt.replace(tzinfo=None), other_dt.replace(tzinfo=None)) + + def test_astimezone(self): + other_tz = pytz.timezone('Europe/Paris') + self.assertTrue(self.tz is not other_tz) + + dt = datetime(2012, 3, 26, 12, 0) + other_dt = other_tz.localize(dt) + + local_dt = other_dt.astimezone(self.tz) + + self.assertTrue(local_dt.tzinfo is not other_dt.tzinfo) + self.assertNotEqual( + local_dt.replace(tzinfo=None), other_dt.replace(tzinfo=None)) + + +class OptimizedUTCTestCase(unittest.TestCase, BaseTzInfoTestCase): + tz = pytz.utc + tz_class = tz.__class__ + + +class LegacyUTCTestCase(unittest.TestCase, BaseTzInfoTestCase): + # Deprecated timezone, but useful for comparison tests. + tz = pytz.timezone('Etc/UTC') + tz_class = StaticTzInfo + + +class StaticTzInfoTestCase(unittest.TestCase, BaseTzInfoTestCase): + tz = pytz.timezone('GMT') + tz_class = StaticTzInfo + + +class DstTzInfoTestCase(unittest.TestCase, BaseTzInfoTestCase): + tz = pytz.timezone('Australia/Melbourne') + tz_class = DstTzInfo + + +def test_suite(): + suite = unittest.TestSuite() + suite.addTest(doctest.DocTestSuite('pytz')) + suite.addTest(doctest.DocTestSuite('pytz.tzinfo')) + import test_tzinfo + suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(test_tzinfo)) + return suite + + +if __name__ == '__main__': + warnings.simplefilter("error") # Warnings should be fatal in tests. + unittest.main(defaultTest='test_suite') diff --git a/lib/pytz/zoneinfo/Africa/Casablanca b/lib/pytz/zoneinfo/Africa/Casablanca index 3ca0fc7a..4c570548 100644 Binary files a/lib/pytz/zoneinfo/Africa/Casablanca and b/lib/pytz/zoneinfo/Africa/Casablanca differ diff --git a/lib/pytz/zoneinfo/Africa/El_Aaiun b/lib/pytz/zoneinfo/Africa/El_Aaiun index e0e15512..0ea02535 100644 Binary files a/lib/pytz/zoneinfo/Africa/El_Aaiun and b/lib/pytz/zoneinfo/Africa/El_Aaiun differ diff --git a/lib/pytz/zoneinfo/Africa/Sao_Tome b/lib/pytz/zoneinfo/Africa/Sao_Tome index d2a64bd1..59f3759c 100644 Binary files a/lib/pytz/zoneinfo/Africa/Sao_Tome and b/lib/pytz/zoneinfo/Africa/Sao_Tome differ diff --git a/lib/pytz/zoneinfo/America/Metlakatla b/lib/pytz/zoneinfo/America/Metlakatla index 26356078..1e94be3d 100644 Binary files a/lib/pytz/zoneinfo/America/Metlakatla and b/lib/pytz/zoneinfo/America/Metlakatla differ diff --git a/lib/pytz/zoneinfo/Asia/Gaza b/lib/pytz/zoneinfo/Asia/Gaza index cf54deb8..32b4ed65 100644 Binary files a/lib/pytz/zoneinfo/Asia/Gaza and b/lib/pytz/zoneinfo/Asia/Gaza differ diff --git a/lib/pytz/zoneinfo/Asia/Hebron b/lib/pytz/zoneinfo/Asia/Hebron index 09c876a6..0ed8b0d4 100644 Binary files a/lib/pytz/zoneinfo/Asia/Hebron and b/lib/pytz/zoneinfo/Asia/Hebron differ diff --git a/lib/pytz/zoneinfo/Asia/Hong_Kong b/lib/pytz/zoneinfo/Asia/Hong_Kong index 8e5c5813..91eaff48 100644 Binary files a/lib/pytz/zoneinfo/Asia/Hong_Kong and b/lib/pytz/zoneinfo/Asia/Hong_Kong differ diff --git a/lib/pytz/zoneinfo/Asia/Jerusalem b/lib/pytz/zoneinfo/Asia/Jerusalem index 2d14c999..93e9f19c 100644 Binary files a/lib/pytz/zoneinfo/Asia/Jerusalem and b/lib/pytz/zoneinfo/Asia/Jerusalem differ diff --git a/lib/pytz/zoneinfo/Asia/Qostanay b/lib/pytz/zoneinfo/Asia/Qostanay new file mode 100644 index 00000000..cb6e2d90 Binary files /dev/null and b/lib/pytz/zoneinfo/Asia/Qostanay differ diff --git a/lib/pytz/zoneinfo/Asia/Qyzylorda b/lib/pytz/zoneinfo/Asia/Qyzylorda index 00b27844..fc636b3b 100644 Binary files a/lib/pytz/zoneinfo/Asia/Qyzylorda and b/lib/pytz/zoneinfo/Asia/Qyzylorda differ diff --git a/lib/pytz/zoneinfo/Asia/Tehran b/lib/pytz/zoneinfo/Asia/Tehran index ad9058b4..0ae2f65f 100644 Binary files a/lib/pytz/zoneinfo/Asia/Tehran and b/lib/pytz/zoneinfo/Asia/Tehran differ diff --git a/lib/pytz/zoneinfo/Asia/Tel_Aviv b/lib/pytz/zoneinfo/Asia/Tel_Aviv index 2d14c999..93e9f19c 100644 Binary files a/lib/pytz/zoneinfo/Asia/Tel_Aviv and b/lib/pytz/zoneinfo/Asia/Tel_Aviv differ diff --git a/lib/pytz/zoneinfo/Etc/UCT b/lib/pytz/zoneinfo/Etc/UCT index a88c4b66..5583f5b0 100644 Binary files a/lib/pytz/zoneinfo/Etc/UCT and b/lib/pytz/zoneinfo/Etc/UCT differ diff --git a/lib/pytz/zoneinfo/Hongkong b/lib/pytz/zoneinfo/Hongkong index 8e5c5813..91eaff48 100644 Binary files a/lib/pytz/zoneinfo/Hongkong and b/lib/pytz/zoneinfo/Hongkong differ diff --git a/lib/pytz/zoneinfo/Iran b/lib/pytz/zoneinfo/Iran index ad9058b4..0ae2f65f 100644 Binary files a/lib/pytz/zoneinfo/Iran and b/lib/pytz/zoneinfo/Iran differ diff --git a/lib/pytz/zoneinfo/Israel b/lib/pytz/zoneinfo/Israel index 2d14c999..93e9f19c 100644 Binary files a/lib/pytz/zoneinfo/Israel and b/lib/pytz/zoneinfo/Israel differ diff --git a/lib/pytz/zoneinfo/Kwajalein b/lib/pytz/zoneinfo/Kwajalein index 54bd71ff..d6413577 100644 Binary files a/lib/pytz/zoneinfo/Kwajalein and b/lib/pytz/zoneinfo/Kwajalein differ diff --git a/lib/pytz/zoneinfo/Pacific/Chuuk b/lib/pytz/zoneinfo/Pacific/Chuuk index e79bca2d..8004d65b 100644 Binary files a/lib/pytz/zoneinfo/Pacific/Chuuk and b/lib/pytz/zoneinfo/Pacific/Chuuk differ diff --git a/lib/pytz/zoneinfo/Pacific/Guam b/lib/pytz/zoneinfo/Pacific/Guam index ffdf8c24..e2242475 100644 Binary files a/lib/pytz/zoneinfo/Pacific/Guam and b/lib/pytz/zoneinfo/Pacific/Guam differ diff --git a/lib/pytz/zoneinfo/Pacific/Honolulu b/lib/pytz/zoneinfo/Pacific/Honolulu index 66eb5c94..c7cd0601 100644 Binary files a/lib/pytz/zoneinfo/Pacific/Honolulu and b/lib/pytz/zoneinfo/Pacific/Honolulu differ diff --git a/lib/pytz/zoneinfo/Pacific/Johnston b/lib/pytz/zoneinfo/Pacific/Johnston index 66eb5c94..c7cd0601 100644 Binary files a/lib/pytz/zoneinfo/Pacific/Johnston and b/lib/pytz/zoneinfo/Pacific/Johnston differ diff --git a/lib/pytz/zoneinfo/Pacific/Kosrae b/lib/pytz/zoneinfo/Pacific/Kosrae index b6bd4b08..11583b13 100644 Binary files a/lib/pytz/zoneinfo/Pacific/Kosrae and b/lib/pytz/zoneinfo/Pacific/Kosrae differ diff --git a/lib/pytz/zoneinfo/Pacific/Kwajalein b/lib/pytz/zoneinfo/Pacific/Kwajalein index 54bd71ff..d6413577 100644 Binary files a/lib/pytz/zoneinfo/Pacific/Kwajalein and b/lib/pytz/zoneinfo/Pacific/Kwajalein differ diff --git a/lib/pytz/zoneinfo/Pacific/Majuro b/lib/pytz/zoneinfo/Pacific/Majuro index 53f32886..65990cbb 100644 Binary files a/lib/pytz/zoneinfo/Pacific/Majuro and b/lib/pytz/zoneinfo/Pacific/Majuro differ diff --git a/lib/pytz/zoneinfo/Pacific/Nauru b/lib/pytz/zoneinfo/Pacific/Nauru index 7e7d920e..86d3b7d1 100644 Binary files a/lib/pytz/zoneinfo/Pacific/Nauru and b/lib/pytz/zoneinfo/Pacific/Nauru differ diff --git a/lib/pytz/zoneinfo/Pacific/Palau b/lib/pytz/zoneinfo/Pacific/Palau index 968f1956..05633b88 100644 Binary files a/lib/pytz/zoneinfo/Pacific/Palau and b/lib/pytz/zoneinfo/Pacific/Palau differ diff --git a/lib/pytz/zoneinfo/Pacific/Pohnpei b/lib/pytz/zoneinfo/Pacific/Pohnpei index d3393a20..090429c0 100644 Binary files a/lib/pytz/zoneinfo/Pacific/Pohnpei and b/lib/pytz/zoneinfo/Pacific/Pohnpei differ diff --git a/lib/pytz/zoneinfo/Pacific/Ponape b/lib/pytz/zoneinfo/Pacific/Ponape index d3393a20..090429c0 100644 Binary files a/lib/pytz/zoneinfo/Pacific/Ponape and b/lib/pytz/zoneinfo/Pacific/Ponape differ diff --git a/lib/pytz/zoneinfo/Pacific/Saipan b/lib/pytz/zoneinfo/Pacific/Saipan index ffdf8c24..e2242475 100644 Binary files a/lib/pytz/zoneinfo/Pacific/Saipan and b/lib/pytz/zoneinfo/Pacific/Saipan differ diff --git a/lib/pytz/zoneinfo/Pacific/Truk b/lib/pytz/zoneinfo/Pacific/Truk index e79bca2d..8004d65b 100644 Binary files a/lib/pytz/zoneinfo/Pacific/Truk and b/lib/pytz/zoneinfo/Pacific/Truk differ diff --git a/lib/pytz/zoneinfo/Pacific/Yap b/lib/pytz/zoneinfo/Pacific/Yap index e79bca2d..8004d65b 100644 Binary files a/lib/pytz/zoneinfo/Pacific/Yap and b/lib/pytz/zoneinfo/Pacific/Yap differ diff --git a/lib/pytz/zoneinfo/UCT b/lib/pytz/zoneinfo/UCT index a88c4b66..5583f5b0 100644 Binary files a/lib/pytz/zoneinfo/UCT and b/lib/pytz/zoneinfo/UCT differ diff --git a/lib/pytz/zoneinfo/US/Hawaii b/lib/pytz/zoneinfo/US/Hawaii index 66eb5c94..c7cd0601 100644 Binary files a/lib/pytz/zoneinfo/US/Hawaii and b/lib/pytz/zoneinfo/US/Hawaii differ diff --git a/lib/pytz/zoneinfo/iso3166.tab b/lib/pytz/zoneinfo/iso3166.tab index c2e0f8ea..a4ff61a4 100644 --- a/lib/pytz/zoneinfo/iso3166.tab +++ b/lib/pytz/zoneinfo/iso3166.tab @@ -9,8 +9,8 @@ # All text uses UTF-8 encoding. The columns of the table are as follows: # # 1. ISO 3166-1 alpha-2 country code, current as of -# ISO 3166-1 N905 (2016-11-15). See: Updates on ISO 3166-1 -# http://isotc.iso.org/livelink/livelink/Open/16944257 +# ISO 3166-1 N976 (2018-11-06). See: Updates on ISO 3166-1 +# https://isotc.iso.org/livelink/livelink/Open/16944257 # 2. The usual English name for the coded region, # chosen so that alphabetic sorting of subsets produces helpful lists. # This is not the same as the English name in the ISO 3166 tables. @@ -166,7 +166,7 @@ ME Montenegro MF St Martin (French) MG Madagascar MH Marshall Islands -MK Macedonia +MK North Macedonia ML Mali MM Myanmar (Burma) MN Mongolia @@ -235,7 +235,7 @@ ST Sao Tome & Principe SV El Salvador SX St Maarten (Dutch) SY Syria -SZ Swaziland +SZ Eswatini (Swaziland) TC Turks & Caicos Is TD Chad TF French Southern & Antarctic Lands diff --git a/lib/pytz/zoneinfo/leapseconds b/lib/pytz/zoneinfo/leapseconds index 148aa8ee..886ae273 100644 --- a/lib/pytz/zoneinfo/leapseconds +++ b/lib/pytz/zoneinfo/leapseconds @@ -19,9 +19,12 @@ # See: Levine J. Coordinated Universal Time and the leap second. # URSI Radio Sci Bull. 2016;89(4):30-6. doi:10.23919/URSIRSB.2016.7909995 # . + # There were no leap seconds before 1972, because the official mechanism # accounting for the discrepancy between atomic time and the earth's rotation -# did not exist. +# did not exist. The first ("1 Jan 1972") data line in leap-seconds.list +# does not denote a leap second; it denotes the start of the current definition +# of UTC. # The correction (+ or -) is made at the given time, so lines # will typically look like: @@ -60,7 +63,7 @@ Leap 2016 Dec 31 23:59:60 + S # POSIX timestamps for the data in this file: #updated 1467936000 -#expires 1561680000 +#expires 1577491200 -# Updated through IERS Bulletin C56 -# File expires on: 28 June 2019 +# Updated through IERS Bulletin C57 +# File expires on: 28 December 2019 diff --git a/lib/pytz/zoneinfo/tzdata.zi b/lib/pytz/zoneinfo/tzdata.zi index 267c6abd..428f440d 100644 --- a/lib/pytz/zoneinfo/tzdata.zi +++ b/lib/pytz/zoneinfo/tzdata.zi @@ -143,67 +143,96 @@ R MU 2008 o - O lastSun 2 1 - R MU 2009 o - Mar lastSun 2 0 - Z Indian/Mauritius 3:50 - LMT 1907 4 MU +04/+05 -R M 1939 o - S 12 0 1 S +R M 1939 o - S 12 0 1 - R M 1939 o - N 19 0 0 - -R M 1940 o - F 25 0 1 S +R M 1940 o - F 25 0 1 - R M 1945 o - N 18 0 0 - -R M 1950 o - Jun 11 0 1 S +R M 1950 o - Jun 11 0 1 - R M 1950 o - O 29 0 0 - -R M 1967 o - Jun 3 12 1 S +R M 1967 o - Jun 3 12 1 - R M 1967 o - O 1 0 0 - -R M 1974 o - Jun 24 0 1 S +R M 1974 o - Jun 24 0 1 - R M 1974 o - S 1 0 0 - -R M 1976 1977 - May 1 0 1 S +R M 1976 1977 - May 1 0 1 - R M 1976 o - Au 1 0 0 - R M 1977 o - S 28 0 0 - -R M 1978 o - Jun 1 0 1 S +R M 1978 o - Jun 1 0 1 - R M 1978 o - Au 4 0 0 - -R M 2008 o - Jun 1 0 1 S +R M 2008 o - Jun 1 0 1 - R M 2008 o - S 1 0 0 - -R M 2009 o - Jun 1 0 1 S +R M 2009 o - Jun 1 0 1 - R M 2009 o - Au 21 0 0 - -R M 2010 o - May 2 0 1 S +R M 2010 o - May 2 0 1 - R M 2010 o - Au 8 0 0 - -R M 2011 o - Ap 3 0 1 S +R M 2011 o - Ap 3 0 1 - R M 2011 o - Jul 31 0 0 - -R M 2012 2013 - Ap lastSun 2 1 S +R M 2012 2013 - Ap lastSun 2 1 - R M 2012 o - Jul 20 3 0 - -R M 2012 o - Au 20 2 1 S +R M 2012 o - Au 20 2 1 - R M 2012 o - S 30 3 0 - R M 2013 o - Jul 7 3 0 - -R M 2013 o - Au 10 2 1 S -R M 2013 ma - O lastSun 3 0 - -R M 2014 2021 - Mar lastSun 2 1 S +R M 2013 o - Au 10 2 1 - +R M 2013 2018 - O lastSun 3 0 - +R M 2014 2018 - Mar lastSun 2 1 - R M 2014 o - Jun 28 3 0 - -R M 2014 o - Au 2 2 1 S +R M 2014 o - Au 2 2 1 - R M 2015 o - Jun 14 3 0 - -R M 2015 o - Jul 19 2 1 S +R M 2015 o - Jul 19 2 1 - R M 2016 o - Jun 5 3 0 - -R M 2016 o - Jul 10 2 1 S +R M 2016 o - Jul 10 2 1 - R M 2017 o - May 21 3 0 - -R M 2017 o - Jul 2 2 1 S +R M 2017 o - Jul 2 2 1 - R M 2018 o - May 13 3 0 - -R M 2018 o - Jun 17 2 1 S -R M 2019 o - May 5 3 0 - -R M 2019 o - Jun 9 2 1 S -R M 2020 o - Ap 19 3 0 - -R M 2020 o - May 24 2 1 S -R M 2021 o - Ap 11 3 0 - -R M 2021 o - May 16 2 1 S -R M 2022 o - May 8 2 1 S -R M 2023 o - Ap 23 2 1 S -R M 2024 o - Ap 14 2 1 S -R M 2025 o - Ap 6 2 1 S -R M 2026 ma - Mar lastSun 2 1 S -R M 2036 o - O 19 3 0 - -R M 2037 o - O 4 3 0 - +R M 2018 o - Jun 17 2 1 - +R M 2019 o - May 5 3 -1 - +R M 2019 o - Jun 9 2 0 - +R M 2020 o - Ap 19 3 -1 - +R M 2020 o - May 24 2 0 - +R M 2021 o - Ap 11 3 -1 - +R M 2021 o - May 16 2 0 - +R M 2022 o - Mar 27 3 -1 - +R M 2022 o - May 8 2 0 - +R M 2023 o - Mar 19 3 -1 - +R M 2023 o - Ap 23 2 0 - +R M 2024 o - Mar 10 3 -1 - +R M 2024 o - Ap 14 2 0 - +R M 2025 o - F 23 3 -1 - +R M 2025 o - Ap 6 2 0 - +R M 2026 o - F 15 3 -1 - +R M 2026 o - Mar 22 2 0 - +R M 2027 o - F 7 3 -1 - +R M 2027 o - Mar 14 2 0 - +R M 2028 o - Ja 23 3 -1 - +R M 2028 o - F 27 2 0 - +R M 2029 o - Ja 14 3 -1 - +R M 2029 o - F 18 2 0 - +R M 2029 o - D 30 3 -1 - +R M 2030 o - F 10 2 0 - +R M 2030 o - D 22 3 -1 - +R M 2031 o - Ja 26 2 0 - +R M 2031 o - D 14 3 -1 - +R M 2032 o - Ja 18 2 0 - +R M 2032 o - N 28 3 -1 - +R M 2033 o - Ja 9 2 0 - +R M 2033 o - N 20 3 -1 - +R M 2033 o - D 25 2 0 - +R M 2034 o - N 5 3 -1 - +R M 2034 o - D 17 2 0 - +R M 2035 o - O 28 3 -1 - +R M 2035 o - D 2 2 0 - +R M 2036 o - O 19 3 -1 - +R M 2036 o - N 23 2 0 - +R M 2037 o - O 4 3 -1 - +R M 2037 o - N 15 2 0 - Z Africa/Casablanca -0:30:20 - LMT 1913 O 26 -0 M WE%sT 1984 Mar 16 -1 - CET 1986 -0 M WE%sT +0 M +00/+01 1984 Mar 16 +1 - +01 1986 +0 M +00/+01 2018 O 28 3 +1 M +01/+00 Z Africa/El_Aaiun -0:52:48 - LMT 1934 -1 - -01 1976 Ap 14 -0 M WE%sT +0 M +00/+01 2018 O 28 3 +1 M +01/+00 Z Africa/Maputo 2:10:20 - LMT 1903 Mar 2 - CAT Li Africa/Maputo Africa/Blantyre @@ -238,7 +267,8 @@ Z Indian/Reunion 3:41:52 - LMT 1911 Jun Z Africa/Sao_Tome 0:26:56 - LMT 1884 -0:36:45 - LMT 1912 Ja 1 0u 0 - GMT 2018 Ja 1 1 -1 - WAT +1 - WAT 2019 Ja 1 2 +0 - GMT Z Indian/Mahe 3:41:48 - LMT 1906 Jun 4 - +04 R SA 1942 1943 - S Sun>=15 2 1 - @@ -386,17 +416,14 @@ Z Asia/Shanghai 8:5:43 - LMT 1901 8 CN C%sT Z Asia/Urumqi 5:50:20 - LMT 1928 6 - +06 -R HK 1941 o - Ap 1 3:30 1 S -R HK 1941 o - S 30 3:30 0 - R HK 1946 o - Ap 20 3:30 1 S R HK 1946 o - D 1 3:30 0 - R HK 1947 o - Ap 13 3:30 1 S R HK 1947 o - D 30 3:30 0 - R HK 1948 o - May 2 3:30 1 S R HK 1948 1951 - O lastSun 3:30 0 - -R HK 1952 o - O 25 3:30 0 - +R HK 1952 1953 - N Sun>=1 3:30 0 - R HK 1949 1953 - Ap Sun>=1 3:30 1 S -R HK 1953 o - N 1 3:30 0 - R HK 1954 1964 - Mar Sun>=18 3:30 1 S R HK 1954 o - O 31 3:30 0 - R HK 1955 1964 - N Sun>=1 3:30 0 - @@ -405,9 +432,11 @@ R HK 1965 1976 - O Sun>=16 3:30 0 - R HK 1973 o - D 30 3:30 1 S R HK 1979 o - May Sun>=8 3:30 1 S R HK 1979 o - O Sun>=16 3:30 0 - -Z Asia/Hong_Kong 7:36:42 - LMT 1904 O 30 -8 HK HK%sT 1941 D 25 -9 - JST 1945 S 15 +Z Asia/Hong_Kong 7:36:42 - LMT 1904 O 30 0:36:42 +8 - HKT 1941 Jun 15 3:30 +8 1 HKST 1941 O 1 4 +8:30 - HKT 1941 D 25 +9 - JST 1945 S 16 8 HK HK%sT R f 1946 o - May 15 0 1 D R f 1946 o - O 1 0 0 S @@ -528,55 +557,107 @@ Z Asia/Jayapura 9:22:48 - LMT 1932 N 9 - +09 1944 S 9:30 - +0930 1964 9 - WIT -R i 1978 1980 - Mar 21 0 1 - -R i 1978 o - O 21 0 0 - -R i 1979 o - S 19 0 0 - -R i 1980 o - S 23 0 0 - -R i 1991 o - May 3 0 1 - -R i 1992 1995 - Mar 22 0 1 - -R i 1991 1995 - S 22 0 0 - -R i 1996 o - Mar 21 0 1 - -R i 1996 o - S 21 0 0 - -R i 1997 1999 - Mar 22 0 1 - -R i 1997 1999 - S 22 0 0 - -R i 2000 o - Mar 21 0 1 - -R i 2000 o - S 21 0 0 - -R i 2001 2003 - Mar 22 0 1 - -R i 2001 2003 - S 22 0 0 - -R i 2004 o - Mar 21 0 1 - -R i 2004 o - S 21 0 0 - -R i 2005 o - Mar 22 0 1 - -R i 2005 o - S 22 0 0 - -R i 2008 o - Mar 21 0 1 - -R i 2008 o - S 21 0 0 - -R i 2009 2011 - Mar 22 0 1 - -R i 2009 2011 - S 22 0 0 - -R i 2012 o - Mar 21 0 1 - -R i 2012 o - S 21 0 0 - -R i 2013 2015 - Mar 22 0 1 - -R i 2013 2015 - S 22 0 0 - -R i 2016 o - Mar 21 0 1 - -R i 2016 o - S 21 0 0 - -R i 2017 2019 - Mar 22 0 1 - -R i 2017 2019 - S 22 0 0 - -R i 2020 o - Mar 21 0 1 - -R i 2020 o - S 21 0 0 - -R i 2021 2023 - Mar 22 0 1 - -R i 2021 2023 - S 22 0 0 - -R i 2024 o - Mar 21 0 1 - -R i 2024 o - S 21 0 0 - -R i 2025 2027 - Mar 22 0 1 - -R i 2025 2027 - S 22 0 0 - -R i 2028 2029 - Mar 21 0 1 - -R i 2028 2029 - S 21 0 0 - -R i 2030 2031 - Mar 22 0 1 - -R i 2030 2031 - S 22 0 0 - -R i 2032 2033 - Mar 21 0 1 - -R i 2032 2033 - S 21 0 0 - -R i 2034 2035 - Mar 22 0 1 - -R i 2034 2035 - S 22 0 0 - -R i 2036 ma - Mar 21 0 1 - -R i 2036 ma - S 21 0 0 - +R i 1978 1980 - Mar 20 24 1 - +R i 1978 o - O 20 24 0 - +R i 1979 o - S 18 24 0 - +R i 1980 o - S 22 24 0 - +R i 1991 o - May 2 24 1 - +R i 1992 1995 - Mar 21 24 1 - +R i 1991 1995 - S 21 24 0 - +R i 1996 o - Mar 20 24 1 - +R i 1996 o - S 20 24 0 - +R i 1997 1999 - Mar 21 24 1 - +R i 1997 1999 - S 21 24 0 - +R i 2000 o - Mar 20 24 1 - +R i 2000 o - S 20 24 0 - +R i 2001 2003 - Mar 21 24 1 - +R i 2001 2003 - S 21 24 0 - +R i 2004 o - Mar 20 24 1 - +R i 2004 o - S 20 24 0 - +R i 2005 o - Mar 21 24 1 - +R i 2005 o - S 21 24 0 - +R i 2008 o - Mar 20 24 1 - +R i 2008 o - S 20 24 0 - +R i 2009 2011 - Mar 21 24 1 - +R i 2009 2011 - S 21 24 0 - +R i 2012 o - Mar 20 24 1 - +R i 2012 o - S 20 24 0 - +R i 2013 2015 - Mar 21 24 1 - +R i 2013 2015 - S 21 24 0 - +R i 2016 o - Mar 20 24 1 - +R i 2016 o - S 20 24 0 - +R i 2017 2019 - Mar 21 24 1 - +R i 2017 2019 - S 21 24 0 - +R i 2020 o - Mar 20 24 1 - +R i 2020 o - S 20 24 0 - +R i 2021 2023 - Mar 21 24 1 - +R i 2021 2023 - S 21 24 0 - +R i 2024 o - Mar 20 24 1 - +R i 2024 o - S 20 24 0 - +R i 2025 2027 - Mar 21 24 1 - +R i 2025 2027 - S 21 24 0 - +R i 2028 2029 - Mar 20 24 1 - +R i 2028 2029 - S 20 24 0 - +R i 2030 2031 - Mar 21 24 1 - +R i 2030 2031 - S 21 24 0 - +R i 2032 2033 - Mar 20 24 1 - +R i 2032 2033 - S 20 24 0 - +R i 2034 2035 - Mar 21 24 1 - +R i 2034 2035 - S 21 24 0 - +R i 2036 2037 - Mar 20 24 1 - +R i 2036 2037 - S 20 24 0 - +R i 2038 2039 - Mar 21 24 1 - +R i 2038 2039 - S 21 24 0 - +R i 2040 2041 - Mar 20 24 1 - +R i 2040 2041 - S 20 24 0 - +R i 2042 2043 - Mar 21 24 1 - +R i 2042 2043 - S 21 24 0 - +R i 2044 2045 - Mar 20 24 1 - +R i 2044 2045 - S 20 24 0 - +R i 2046 2047 - Mar 21 24 1 - +R i 2046 2047 - S 21 24 0 - +R i 2048 2049 - Mar 20 24 1 - +R i 2048 2049 - S 20 24 0 - +R i 2050 2051 - Mar 21 24 1 - +R i 2050 2051 - S 21 24 0 - +R i 2052 2053 - Mar 20 24 1 - +R i 2052 2053 - S 20 24 0 - +R i 2054 2055 - Mar 21 24 1 - +R i 2054 2055 - S 21 24 0 - +R i 2056 2057 - Mar 20 24 1 - +R i 2056 2057 - S 20 24 0 - +R i 2058 2059 - Mar 21 24 1 - +R i 2058 2059 - S 21 24 0 - +R i 2060 2062 - Mar 20 24 1 - +R i 2060 2062 - S 20 24 0 - +R i 2063 o - Mar 21 24 1 - +R i 2063 o - S 21 24 0 - +R i 2064 2066 - Mar 20 24 1 - +R i 2064 2066 - S 20 24 0 - +R i 2067 o - Mar 21 24 1 - +R i 2067 o - S 21 24 0 - +R i 2068 2070 - Mar 20 24 1 - +R i 2068 2070 - S 20 24 0 - +R i 2071 o - Mar 21 24 1 - +R i 2071 o - S 21 24 0 - +R i 2072 2074 - Mar 20 24 1 - +R i 2072 2074 - S 20 24 0 - +R i 2075 o - Mar 21 24 1 - +R i 2075 o - S 21 24 0 - +R i 2076 2078 - Mar 20 24 1 - +R i 2076 2078 - S 20 24 0 - +R i 2079 o - Mar 21 24 1 - +R i 2079 o - S 21 24 0 - +R i 2080 2082 - Mar 20 24 1 - +R i 2080 2082 - S 20 24 0 - +R i 2083 o - Mar 21 24 1 - +R i 2083 o - S 21 24 0 - +R i 2084 2086 - Mar 20 24 1 - +R i 2084 2086 - S 20 24 0 - +R i 2087 o - Mar 21 24 1 - +R i 2087 o - S 21 24 0 - +R i 2088 ma - Mar 20 24 1 - +R i 2088 ma - S 20 24 0 - Z Asia/Tehran 3:25:44 - LMT 1916 3:25:44 - TMT 1946 3:30 - +0330 1977 N @@ -626,6 +707,10 @@ R Z 1974 o - Jul 7 0 1 D R Z 1974 o - O 13 0 0 S R Z 1975 o - Ap 20 0 1 D R Z 1975 o - Au 31 0 0 S +R Z 1980 o - Au 2 0 1 D +R Z 1980 o - S 13 1 0 S +R Z 1984 o - May 5 0 1 D +R Z 1984 o - Au 25 1 0 S R Z 1985 o - Ap 14 0 1 D R Z 1985 o - S 15 0 0 S R Z 1986 o - May 18 0 1 D @@ -738,6 +823,16 @@ Z Asia/Qyzylorda 4:21:52 - LMT 1924 May 2 5 R +05/+06 1992 Ja 19 2s 6 R +06/+07 1992 Mar 29 2s 5 R +05/+06 2004 O 31 2s +6 - +06 2018 D 21 +5 - +05 +Z Asia/Qostanay 4:14:28 - LMT 1924 May 2 +4 - +04 1930 Jun 21 +5 - +05 1981 Ap +5 1 +06 1981 O +6 - +06 1982 Ap +5 R +05/+06 1991 Mar 31 2s +4 R +04/+05 1992 Ja 19 2s +5 R +05/+06 2004 O 31 2s 6 - +06 Z Asia/Aqtobe 3:48:40 - LMT 1924 May 2 4 - +04 1930 Jun 21 @@ -787,17 +882,17 @@ Z Asia/Bishkek 4:58:24 - LMT 1924 May 2 5 KG +05/+06 2005 Au 12 6 - +06 R KR 1948 o - Jun 1 0 1 D -R KR 1948 o - S 13 0 0 S +R KR 1948 o - S 12 24 0 S R KR 1949 o - Ap 3 0 1 D -R KR 1949 1951 - S Sun>=8 0 0 S +R KR 1949 1951 - S Sat>=7 24 0 S R KR 1950 o - Ap 1 0 1 D R KR 1951 o - May 6 0 1 D R KR 1955 o - May 5 0 1 D -R KR 1955 o - S 9 0 0 S +R KR 1955 o - S 8 24 0 S R KR 1956 o - May 20 0 1 D -R KR 1956 o - S 30 0 0 S +R KR 1956 o - S 29 24 0 S R KR 1957 1960 - May Sun>=1 0 1 D -R KR 1957 1960 - S Sun>=18 0 0 S +R KR 1957 1960 - S Sat>=17 24 0 S R KR 1987 1988 - May Sun>=8 2 1 D R KR 1987 1988 - O Sun>=8 3 0 S Z Asia/Seoul 8:27:52 - LMT 1908 Ap @@ -912,7 +1007,7 @@ R P 2012 o - S 21 1 0 - R P 2013 o - S F>=21 0 0 - R P 2014 2015 - O F>=21 0 0 - R P 2015 o - Mar lastF 24 1 S -R P 2016 ma - Mar Sat>=22 1 1 S +R P 2016 ma - Mar Sat>=24 1 1 S R P 2016 ma - O lastSat 1 0 - Z Asia/Gaza 2:17:52 - LMT 1900 O 2 Z EET/EEST 1948 May 15 @@ -1228,9 +1323,25 @@ Z Pacific/Marquesas -9:18 - LMT 1912 O -9:30 - -0930 Z Pacific/Tahiti -9:58:16 - LMT 1912 O -10 - -10 +R Gu 1959 o - Jun 27 2 1 D +R Gu 1961 o - Ja 29 2 0 S +R Gu 1967 o - S 1 2 1 D +R Gu 1969 o - Ja 26 0:1 0 S +R Gu 1969 o - Jun 22 2 1 D +R Gu 1969 o - Au 31 2 0 S +R Gu 1970 1971 - Ap lastSun 2 1 D +R Gu 1970 1971 - S Sun>=1 2 0 S +R Gu 1973 o - D 16 2 1 D +R Gu 1974 o - F 24 2 0 S +R Gu 1976 o - May 26 2 1 D +R Gu 1976 o - Au 22 2:1 0 S +R Gu 1977 o - Ap 24 2 1 D +R Gu 1977 o - Au 28 2 0 S Z Pacific/Guam -14:21 - LMT 1844 D 31 9:39 - LMT 1901 -10 - GST 2000 D 23 +10 - GST 1941 D 10 +9 - +09 1944 Jul 31 +10 Gu G%sT 2000 D 23 10 - ChST Li Pacific/Guam Pacific/Saipan Z Pacific/Tarawa 11:32:4 - LMT 1901 @@ -1244,24 +1355,49 @@ Z Pacific/Kiritimati -10:29:20 - LMT 1901 -10 - -10 1994 D 31 14 - +14 Z Pacific/Majuro 11:24:48 - LMT 1901 +11 - +11 1914 O +9 - +09 1919 F +11 - +11 1937 +10 - +10 1941 Ap +9 - +09 1944 Ja 30 11 - +11 1969 O 12 - +12 Z Pacific/Kwajalein 11:9:20 - LMT 1901 +11 - +11 1937 +10 - +10 1941 Ap +9 - +09 1944 F 6 11 - +11 1969 O --12 - -12 1993 Au 20 +-12 - -12 1993 Au 20 24 12 - +12 -Z Pacific/Chuuk 10:7:8 - LMT 1901 +Z Pacific/Chuuk -13:52:52 - LMT 1844 D 31 +10:7:8 - LMT 1901 +10 - +10 1914 O +9 - +09 1919 F +10 - +10 1941 Ap +9 - +09 1945 Au 10 - +10 -Z Pacific/Pohnpei 10:32:52 - LMT 1901 +Z Pacific/Pohnpei -13:27:8 - LMT 1844 D 31 +10:32:52 - LMT 1901 +11 - +11 1914 O +9 - +09 1919 F +11 - +11 1937 +10 - +10 1941 Ap +9 - +09 1945 Au 11 - +11 -Z Pacific/Kosrae 10:51:56 - LMT 1901 +Z Pacific/Kosrae -13:8:4 - LMT 1844 D 31 +10:51:56 - LMT 1901 +11 - +11 1914 O +9 - +09 1919 F +11 - +11 1937 +10 - +10 1941 Ap +9 - +09 1945 Au 11 - +11 1969 O 12 - +12 1999 11 - +11 Z Pacific/Nauru 11:7:40 - LMT 1921 Ja 15 -11:30 - +1130 1942 Mar 15 -9 - +09 1944 Au 15 -11:30 - +1130 1979 May +11:30 - +1130 1942 Au 29 +9 - +09 1945 S 8 +11:30 - +1130 1979 F 10 2 12 - +12 R NC 1977 1978 - D Sun>=1 0 1 - R NC 1978 1979 - F 27 0 0 - @@ -1317,7 +1453,8 @@ Z Pacific/Norfolk 11:11:52 - LMT 1901 11:30 1 +1230 1975 Mar 2 2 11:30 - +1130 2015 O 4 2 11 - +11 -Z Pacific/Palau 8:57:56 - LMT 1901 +Z Pacific/Palau -15:2:4 - LMT 1844 D 31 +8:57:56 - LMT 1901 9 - +09 Z Pacific/Port_Moresby 9:48:40 - LMT 1880 9:48:32 - PMMT 1895 @@ -2433,6 +2570,15 @@ R s 1976 1977 - S lastSun 1 0 - R s 1977 o - Ap 2 23 1 S R s 1978 o - Ap 2 2s 1 S R s 1978 o - O 1 2s 0 - +R Sp 1967 o - Jun 3 12 1 S +R Sp 1967 o - O 1 0 0 - +R Sp 1974 o - Jun 24 0 1 S +R Sp 1974 o - S 1 0 0 - +R Sp 1976 1977 - May 1 0 1 S +R Sp 1976 o - Au 1 0 0 - +R Sp 1977 o - S 28 0 0 - +R Sp 1978 o - Jun 1 0 1 S +R Sp 1978 o - Au 4 0 0 - Z Europe/Madrid -0:14:44 - LMT 1900 D 31 23:45:16 0 s WE%sT 1940 Mar 16 23 1 s CE%sT 1979 @@ -2443,7 +2589,7 @@ Z Africa/Ceuta -0:21:16 - LMT 1900 D 31 23:38:44 0 - WET 1924 0 s WE%sT 1929 0 - WET 1967 -0 M WE%sT 1984 Mar 16 +0 Sp WE%sT 1984 Mar 16 1 - CET 1986 1 E CE%sT Z Atlantic/Canary -1:1:36 - LMT 1922 Mar @@ -2658,6 +2804,8 @@ Z America/Metlakatla 15:13:42 - LMT 1867 O 19 15:44:55 -8 - PST 1969 -8 u P%sT 1983 O 30 2 -8 - PST 2015 N 1 2 +-9 u AK%sT 2018 N 4 2 +-8 - PST 2019 Ja 20 2 -9 u AK%sT Z America/Yakutat 14:41:5 - LMT 1867 O 19 15:12:18 -9:18:55 - LMT 1900 Au 20 12 @@ -2695,9 +2843,7 @@ Z America/Adak 12:13:22 - LMT 1867 O 19 12:44:35 Z Pacific/Honolulu -10:31:26 - LMT 1896 Ja 13 12 -10:30 - HST 1933 Ap 30 2 -10:30 1 HDT 1933 May 21 12 --10:30 - HST 1942 F 9 2 --10:30 1 HDT 1945 S 30 2 --10:30 - HST 1947 Jun 8 2 +-10:30 u H%sT 1947 Jun 8 2 -10 - HST Z America/Phoenix -7:28:18 - LMT 1883 N 18 11:31:42 -7 u M%sT 1944 Ja 1 0:1 @@ -4026,7 +4172,6 @@ Z America/Caracas -4:27:44 - LMT 1890 -4 - -04 Z Etc/GMT 0 - GMT Z Etc/UTC 0 - UTC -Z Etc/UCT 0 - UCT Li Etc/GMT GMT Li Etc/UTC Etc/Universal Li Etc/UTC Etc/Zulu @@ -4128,6 +4273,7 @@ Li Pacific/Easter Chile/EasterIsland Li America/Havana Cuba Li Africa/Cairo Egypt Li Europe/Dublin Eire +Li Etc/UTC Etc/UCT Li Europe/London Europe/Belfast Li Europe/Chisinau Europe/Tiraspol Li Europe/London GB @@ -4162,7 +4308,7 @@ Li Asia/Taipei ROC Li Asia/Seoul ROK Li Asia/Singapore Singapore Li Europe/Istanbul Turkey -Li Etc/UCT UCT +Li Etc/UTC UCT Li America/Anchorage US/Alaska Li America/Adak US/Aleutian Li America/Phoenix US/Arizona diff --git a/lib/pytz/zoneinfo/zone.tab b/lib/pytz/zoneinfo/zone.tab index dcb6e1da..27e1dee6 100644 --- a/lib/pytz/zoneinfo/zone.tab +++ b/lib/pytz/zoneinfo/zone.tab @@ -239,6 +239,7 @@ KW +2920+04759 Asia/Kuwait KY +1918-08123 America/Cayman KZ +4315+07657 Asia/Almaty Kazakhstan (most areas) KZ +4448+06528 Asia/Qyzylorda Qyzylorda/Kyzylorda/Kzyl-Orda +KZ +5312+06337 Asia/Qostanay Qostanay/Kostanay/Kustanay KZ +5017+05710 Asia/Aqtobe Aqtobe/Aktobe KZ +4431+05016 Asia/Aqtau Mangghystau/Mankistau KZ +4707+05156 Asia/Atyrau Atyrau/Atirau/Gur'yev @@ -332,9 +333,9 @@ RS +4450+02030 Europe/Belgrade RU +5443+02030 Europe/Kaliningrad MSK-01 - Kaliningrad RU +554521+0373704 Europe/Moscow MSK+00 - Moscow area RU +4457+03406 Europe/Simferopol MSK+00 - Crimea -RU +4844+04425 Europe/Volgograd MSK+00 - Volgograd RU +5836+04939 Europe/Kirov MSK+00 - Kirov RU +4621+04803 Europe/Astrakhan MSK+01 - Astrakhan +RU +4844+04425 Europe/Volgograd MSK+01 - Volgograd RU +5134+04602 Europe/Saratov MSK+01 - Saratov RU +5420+04824 Europe/Ulyanovsk MSK+01 - Ulyanovsk RU +5312+05009 Europe/Samara MSK+01 - Samara, Udmurtia diff --git a/lib/pytz/zoneinfo/zone1970.tab b/lib/pytz/zoneinfo/zone1970.tab index 7c86fb69..9a8e4244 100644 --- a/lib/pytz/zoneinfo/zone1970.tab +++ b/lib/pytz/zoneinfo/zone1970.tab @@ -211,6 +211,7 @@ KP +3901+12545 Asia/Pyongyang KR +3733+12658 Asia/Seoul KZ +4315+07657 Asia/Almaty Kazakhstan (most areas) KZ +4448+06528 Asia/Qyzylorda Qyzylorda/Kyzylorda/Kzyl-Orda +KZ +5312+06337 Asia/Qostanay Qostanay/Kostanay/Kustanay KZ +5017+05710 Asia/Aqtobe Aqtöbe/Aktobe KZ +4431+05016 Asia/Aqtau Mangghystaū/Mankistau KZ +4707+05156 Asia/Atyrau Atyraū/Atirau/Gur'yev @@ -289,9 +290,9 @@ RS,BA,HR,ME,MK,SI +4450+02030 Europe/Belgrade RU +5443+02030 Europe/Kaliningrad MSK-01 - Kaliningrad RU +554521+0373704 Europe/Moscow MSK+00 - Moscow area RU +4457+03406 Europe/Simferopol MSK+00 - Crimea -RU +4844+04425 Europe/Volgograd MSK+00 - Volgograd RU +5836+04939 Europe/Kirov MSK+00 - Kirov RU +4621+04803 Europe/Astrakhan MSK+01 - Astrakhan +RU +4844+04425 Europe/Volgograd MSK+01 - Volgograd RU +5134+04602 Europe/Saratov MSK+01 - Saratov RU +5420+04824 Europe/Ulyanovsk MSK+01 - Ulyanovsk RU +5312+05009 Europe/Samara MSK+01 - Samara, Udmurtia