From 1e2901810fee9049f6a376010cd0ecfb0e1c87bf Mon Sep 17 00:00:00 2001 From: Bas Stottelaar Date: Tue, 27 Jan 2015 22:03:18 +0100 Subject: [PATCH] Upgraded PyTZ to 2014.10 --- lib/pytz/README.txt | 575 +++++++++++++++++ lib/pytz/__init__.py | 6 +- lib/pytz/tests/test_docs.py | 34 - lib/pytz/tests/test_lazy.py | 313 ---------- lib/pytz/tests/test_tzinfo.py | 820 ------------------------- lib/pytz/tzinfo.py | 17 +- lib/pytz/zoneinfo/Africa/Addis_Ababa | Bin 206 -> 283 bytes lib/pytz/zoneinfo/Africa/Asmara | Bin 227 -> 283 bytes lib/pytz/zoneinfo/Africa/Asmera | Bin 227 -> 283 bytes lib/pytz/zoneinfo/Africa/Blantyre | Bin 171 -> 171 bytes lib/pytz/zoneinfo/Africa/Bujumbura | Bin 149 -> 171 bytes lib/pytz/zoneinfo/Africa/Dar_es_Salaam | Bin 243 -> 283 bytes lib/pytz/zoneinfo/Africa/Djibouti | Bin 171 -> 283 bytes lib/pytz/zoneinfo/Africa/Gaborone | Bin 260 -> 171 bytes lib/pytz/zoneinfo/Africa/Harare | Bin 171 -> 171 bytes lib/pytz/zoneinfo/Africa/Kampala | Bin 283 -> 283 bytes lib/pytz/zoneinfo/Africa/Kigali | Bin 171 -> 171 bytes lib/pytz/zoneinfo/Africa/Lubumbashi | Bin 149 -> 171 bytes lib/pytz/zoneinfo/Africa/Lusaka | Bin 171 -> 171 bytes lib/pytz/zoneinfo/Africa/Maseru | Bin 218 -> 271 bytes lib/pytz/zoneinfo/Africa/Mbabane | Bin 174 -> 271 bytes lib/pytz/zoneinfo/Africa/Mogadishu | Bin 236 -> 283 bytes lib/pytz/zoneinfo/America/Grand_Turk | Bin 1259 -> 1287 bytes lib/pytz/zoneinfo/America/Jamaica | Bin 507 -> 507 bytes lib/pytz/zoneinfo/Asia/Ho_Chi_Minh | Bin 269 -> 373 bytes lib/pytz/zoneinfo/Asia/Novokuznetsk | Bin 1248 -> 1248 bytes lib/pytz/zoneinfo/Asia/Phnom_Penh | Bin 269 -> 204 bytes lib/pytz/zoneinfo/Asia/Pyongyang | Bin 362 -> 279 bytes lib/pytz/zoneinfo/Asia/Saigon | Bin 269 -> 373 bytes lib/pytz/zoneinfo/Asia/Seoul | Bin 500 -> 571 bytes lib/pytz/zoneinfo/Asia/Vientiane | Bin 269 -> 204 bytes lib/pytz/zoneinfo/Europe/Minsk | Bin 1354 -> 1368 bytes lib/pytz/zoneinfo/Indian/Antananarivo | Bin 241 -> 283 bytes lib/pytz/zoneinfo/Indian/Comoro | Bin 171 -> 283 bytes lib/pytz/zoneinfo/Indian/Mayotte | Bin 171 -> 283 bytes lib/pytz/zoneinfo/Jamaica | Bin 507 -> 507 bytes lib/pytz/zoneinfo/Pacific/Bougainville | Bin 0 -> 280 bytes lib/pytz/zoneinfo/Pacific/Fiji | Bin 1078 -> 1074 bytes lib/pytz/zoneinfo/ROK | Bin 500 -> 571 bytes lib/pytz/zoneinfo/zone.tab | 3 +- lib/pytz/zoneinfo/zone1970.tab | 8 +- 41 files changed, 595 insertions(+), 1181 deletions(-) create mode 100644 lib/pytz/README.txt delete mode 100644 lib/pytz/tests/test_docs.py delete mode 100644 lib/pytz/tests/test_lazy.py delete mode 100644 lib/pytz/tests/test_tzinfo.py create mode 100644 lib/pytz/zoneinfo/Pacific/Bougainville diff --git a/lib/pytz/README.txt b/lib/pytz/README.txt new file mode 100644 index 00000000..8b216960 --- /dev/null +++ b/lib/pytz/README.txt @@ -0,0 +1,575 @@ +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) +'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) +'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 also needs special attention. We also need +to use the ``normalize()`` method to ensure the conversion is correct. + +>>> 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 = au_tz.normalize(utc_dt.astimezone(au_tz)) +>>> au_dt.strftime(fmt) +'2006-03-27 08:34:59 AEDT+1100' +>>> utc_dt2 = utc.normalize(au_dt.astimezone(utc)) +>>> utc_dt2.strftime(fmt) +'2006-03-26 21:34:59 UTC+0000' + +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 resulve 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 +>>> 'US/Pacific-New' in all_timezones +True +>>> 'US/Pacific-New' 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 + + +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 the `Bazaar version control system `_ +using:: + + bzr branch lp: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 da80e710..e5cbe56d 100644 --- a/lib/pytz/__init__.py +++ b/lib/pytz/__init__.py @@ -9,8 +9,8 @@ on how to use these modules. ''' # The Olson database is updated several times a year. -OLSON_VERSION = '2014g' -VERSION = '2014.7' # Switching to pip compatible version numbering. +OLSON_VERSION = '2014j' +VERSION = '2014.10' # Switching to pip compatible version numbering. __version__ = VERSION OLSEN_VERSION = OLSON_VERSION # Old releases had this misspelling @@ -1004,6 +1004,7 @@ all_timezones = \ 'PST8PDT', 'Pacific/Apia', 'Pacific/Auckland', + 'Pacific/Bougainville', 'Pacific/Chatham', 'Pacific/Chuuk', 'Pacific/Easter', @@ -1461,6 +1462,7 @@ common_timezones = \ 'Indian/Reunion', 'Pacific/Apia', 'Pacific/Auckland', + 'Pacific/Bougainville', 'Pacific/Chatham', 'Pacific/Chuuk', 'Pacific/Easter', diff --git a/lib/pytz/tests/test_docs.py b/lib/pytz/tests/test_docs.py deleted file mode 100644 index fb49ec15..00000000 --- a/lib/pytz/tests/test_docs.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- coding: ascii -*- - -from doctest import DocFileSuite -import unittest, os.path, 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('US-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 deleted file mode 100644 index 3a4afa63..00000000 --- a/lib/pytz/tests/test_lazy.py +++ /dev/null @@ -1,313 +0,0 @@ -from operator import * -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(self.lazy, op)(set([1])), - getattr(self.base, op)(set([1])), op) - self.assertEqual(self.lazy, self.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 deleted file mode 100644 index 5a929597..00000000 --- a/lib/pytz/tests/test_tzinfo.py +++ /dev/null @@ -1,820 +0,0 @@ -# -*- coding: ascii -*- - -import sys, os, os.path -import unittest, doctest -try: - import cPickle as pickle -except ImportError: - import pickle -from datetime import datetime, time, timedelta, tzinfo -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 -from pytz import reference -from pytz.tzfile import _byte_string -from pytz.tzinfo import DstTzInfo, StaticTzInfo - -# I test for expected version to ensure the correct version of pytz is -# actually being tested. -EXPECTED_VERSION='2014.7' -EXPECTED_OLSON_VERSION='2014g' - -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) - - -try: - unicode -except NameError: - # 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'))) - - -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): - dt = datetime(2004, 2, 1, 0, 0, 0) - 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('???')) - 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': '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': 'NCST', - 'utcoffset': timedelta(hours=12), - 'dst': timedelta(hours=1), - } - after = { - 'tzname': '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': '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': 'SDT', - 'utcoffset': timedelta(hours=-10), - 'dst': timedelta(hours=1), - } - after = { - 'tzname': '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)) - self.assertEqual(loc_time.strftime('%Z%z'), 'NET+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') - - tz = pytz.timezone('Europe/Amsterdam') - 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') - - 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 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/tzinfo.py b/lib/pytz/tzinfo.py index d53e9ff1..1318872d 100644 --- a/lib/pytz/tzinfo.py +++ b/lib/pytz/tzinfo.py @@ -142,7 +142,7 @@ class StaticTzInfo(BaseTzInfo): def __reduce__(self): # Special pickle to zone remains a singleton and to cope with - # database changes. + # database changes. return pytz._p, (self.zone,) @@ -369,13 +369,15 @@ class DstTzInfo(BaseTzInfo): # hints to be passed in (such as the UTC offset or abbreviation), # but that is just getting silly. # - # Choose the earliest (by UTC) applicable timezone. - sorting_keys = {} + # Choose the earliest (by UTC) applicable timezone if is_dst=True + # Choose the latest (by UTC) applicable timezone if is_dst=False + # i.e., behave like end-of-DST transition + dates = {} # utc -> local for local_dt in filtered_possible_loc_dt: - key = local_dt.replace(tzinfo=None) - local_dt.tzinfo._utcoffset - sorting_keys[key] = local_dt - first_key = sorted(sorting_keys)[0] - return sorting_keys[first_key] + utc_time = local_dt.replace(tzinfo=None) - local_dt.tzinfo._utcoffset + assert utc_time not in dates + dates[utc_time] = local_dt + return dates[[min, max][not is_dst](dates)] def utcoffset(self, dt, is_dst=None): '''See datetime.tzinfo.utcoffset @@ -560,4 +562,3 @@ def unpickler(zone, utcoffset=None, dstoffset=None, tzname=None): inf = (utcoffset, dstoffset, tzname) tz._tzinfos[inf] = tz.__class__(inf, tz._tzinfos) return tz._tzinfos[inf] - diff --git a/lib/pytz/zoneinfo/Africa/Addis_Ababa b/lib/pytz/zoneinfo/Africa/Addis_Ababa index 4dfa06ab707b070064d6883ce8d313ef170c6fba..750d3dc14cabc52517d6be5d76da4080f213f4fc 100644 GIT binary patch literal 283 zcmWHE%1kq2zyPd35fBCe7+bgj$l3Vr)}JkhW?eWw(f!6-{fAc=7@3$E85opWKq|Ei z7+4q>lrlr&l?(lr&l?(|3HA>R4$lro2?)O1r|q$i&FNpmGJINXr1EPHhbX x2ZZh88^Yk~7{cJ>>KGaVQUC@aB-r)?s^>otfNTZPAe%undA4%_9i(f_1pwN^Et3EM diff --git a/lib/pytz/zoneinfo/Africa/Djibouti b/lib/pytz/zoneinfo/Africa/Djibouti index 559aabc163c2d91db0567305afcc46b71325518e..750d3dc14cabc52517d6be5d76da4080f213f4fc 100644 GIT binary patch literal 283 zcmWHE%1kq2zyPd35fBCe7+bgj$l3Vr)}JkhW?eWw(f!6-{fAc=7@3$E85opWKq|Ei z7+4q>lryt$|A7F%sa!zgb&a_IrQ8&W diff --git a/lib/pytz/zoneinfo/Africa/Gaborone b/lib/pytz/zoneinfo/Africa/Gaborone index 424534c49804be58b6a4dc9817e01e65a321676e..5b871dbaa7c2969f6b4dfc854184a29010bfb2cc 100644 GIT binary patch literal 171 zcmWHE%1kq2zyM4@5fBCe7@MO3$Z2vr`h|g!fkCbZBqgK3z~bW@!r<%}0^%}+kYL&m Tunq=>|3HA>R4$bTtLU^8gT&tHG?k_ diff --git a/lib/pytz/zoneinfo/Africa/Harare b/lib/pytz/zoneinfo/Africa/Harare index 0e53de0a33f1b960077d29b293c8c786d3636575..5b871dbaa7c2969f6b4dfc854184a29010bfb2cc 100644 GIT binary patch delta 33 gcmZ3@xSDZ-5y#Ol42%p6ay=6#h)ndeLgGpT0Jk~{eEw JKs1_4I{@P)C>;O* delta 75 zcmbQuG@EIHk@$U?Er(`ZxHh-##`7Nc5C%pjW<~}Exs-`_%_lZkDc_g*4+J0;AR43! JM5C#+0|0EFB~1VT diff --git a/lib/pytz/zoneinfo/Africa/Kigali b/lib/pytz/zoneinfo/Africa/Kigali index b99c20940b2d7063578f53cd42e0acc194856c34..5b871dbaa7c2969f6b4dfc854184a29010bfb2cc 100644 GIT binary patch delta 37 icmZ3@xSDZ-0augT(Ju^)3=DET6DNpF^s_(_kOlziLJSQ6 delta 37 icmZ3@xSDZ-0oT5dd;tuM3=A>`6DNpF^s_(_kOlzK@(O7H diff --git a/lib/pytz/zoneinfo/Africa/Lubumbashi b/lib/pytz/zoneinfo/Africa/Lubumbashi index 05aad3c8a5803fb19d934ed57966edd3b9ee07a0..5b871dbaa7c2969f6b4dfc854184a29010bfb2cc 100644 GIT binary patch literal 171 zcmWHE%1kq2zyM4@5fBCe7@MO3$Z2vr`h|g!fkCbZBqgK3z~bW@!r<%}0^%}+kYL&m Tunq=>|3HA>R4$GwXU9&d$p(IMKUsi;r&zL$G6T2uKbLLI_*Q4pa!X@&{DUe;~-Mc60#IASZxm ckTXCu$SEKiGwXU9&d$p(IMKUsi;r&zL$G6T2uKbLLI_*Q4pa!X@&{DUe;~-Mc60#IASZxm ckTXCu$SEKiKuKz#yvul9EwiVDa${VF-2%4gv8QLP#*~ U2UrIK!+#(kU@RBN0$n360C8Uv%>V!Z diff --git a/lib/pytz/zoneinfo/Africa/Mogadishu b/lib/pytz/zoneinfo/Africa/Mogadishu index 3c278ab236a331541bf960bc18dd07ba4130745b..750d3dc14cabc52517d6be5d76da4080f213f4fc 100644 GIT binary patch literal 283 zcmWHE%1kq2zyPd35fBCe7+bgj$l3Vr)}JkhW?eWw(f!6-{fAc=7@3$E85opWKq|Ei z7+4q>lrUI}e delta 46 ucmZqYdd)dOnbB*biUA`db1)?`!3FHuxEzB+Ot=6is|&dR diff --git a/lib/pytz/zoneinfo/America/Jamaica b/lib/pytz/zoneinfo/America/Jamaica index 24ea5dc09ba72f032adfdb753605764f13105849..006689bc895854db5deb33a29ff5d99c6c205fc6 100644 GIT binary patch delta 21 acmey({F`}#2{U`I0sM&!Z2$lO delta 37 ocmaFB`G9kR0n5Ul!VVivS{NDqChufS2Xi;8FtsoN`72q>0Sj#n2LJ#7 diff --git a/lib/pytz/zoneinfo/Asia/Phnom_Penh b/lib/pytz/zoneinfo/Asia/Phnom_Penh index 37c9e15fb9bc06bb3ca2af8e420e6df2f632a176..e8e76276a657ffea33afc25ea56864eddc7f43eb 100644 GIT binary patch literal 204 zcmWHE%1kq2zyQoZ5fBCeCLji}c^ZJkqO9~Ij6jh%8z2WnvM?|t6)Pb^?yWMXDvU?_b8Qd!=? z0A$xqVBi3gykL^W$2Ww*J2-^F%NaxfF#?2;VEYfKw*No?as`M6xdcRmTmzyhcM%uR IrMi|}0N&#}>i_@% literal 362 zcmWHE%1kq2zyRz(5fBCe4j=}x1si}w>*TtM4gY#S>}c6iaX8ev;F5k~!6Sdo4w{@CICrZFbNbXXn=~d`1pn}cn60tcsYXzAVvit zgdN8T)B$$f52)7vK#wSaLHNy!y|vq4^OhU|9C1a zk?|~vx#GE?&x;rO1r;xzf5~{oA5`(`__d7J?@cP+EZ>pw_PkidyY^WbA504?6c#5; zP|Qo8pw#R%LD|o90s|uxGYcat5@cZmLI#F%4xp_JkLLg z28NymjDkMCAq?KZAq-y5AOeWJT|z)Qkw6Fue*FQ}_a6vAeg@GXe}ia{-$69U{~#I^ z1|S*~4j>v779biF9v~VNCLkIVE?^oMHXs@lK42OcMj#p#P9Pc-Rv;P_ULYD2W*{0A dZXjoY!VW}(!Vg4)!VpB$D;&9i;jC-P1ptE4#?=4- literal 500 zcmWHE%1kq2zyO>;5fBCeejo<1MH_%b>*TtM4gY#S>}c6iaX8ev;F7cYhe!UJAKpHk z)bOs6^TP+ziiW>Sxqc`tb}3NIvrSNHRx42UlTTn|Vq{`wVPj=uWMKzF28MDDplJ-{ z9SlHr-2?_84@mNYNw5f`AOk}|14y=K0f-HhW%2P1Vek$PVeoPW5kTzi5&|*>4TKQ( zlK@Z)*iS#8djA7KW?M=Hhz9u)M1%YZqCtKI(IEeVXpo;lG|1l|8sv8n4e~#T2898L i289F2cu-h?Xi#{7Xi%7dXi&H?&@*7TfPtrL$prw{(u!38 diff --git a/lib/pytz/zoneinfo/Asia/Vientiane b/lib/pytz/zoneinfo/Asia/Vientiane index 67e90e0cf8c4cf4d0dd3b8ea79a8a4bcfbb3d935..e8e76276a657ffea33afc25ea56864eddc7f43eb 100644 GIT binary patch literal 204 zcmWHE%1kq2zyQoZ5fBCeCLji}c^ZJkqO9~Ij6jh%8z2WnvM?|t6)$vSfmC``EeMTtjq?xd1K)44eP} diff --git a/lib/pytz/zoneinfo/Indian/Antananarivo b/lib/pytz/zoneinfo/Indian/Antananarivo index 33d59cc974aed5ebf3241db24af1c272281473ac..750d3dc14cabc52517d6be5d76da4080f213f4fc 100644 GIT binary patch literal 283 zcmWHE%1kq2zyPd35fBCe7+bgj$l3Vr)}JkhW?eWw(f!6-{fAc=7@3$E85opWKq|Ei z7+4q>lrRNKpt0mi+)}0D}KO0J0QBgDeKqlra1{NRR5C&Jr5D=Fkgap%m UfORl1{09R3rg8y|*EQw>06qT}hX4Qo diff --git a/lib/pytz/zoneinfo/Indian/Mayotte b/lib/pytz/zoneinfo/Indian/Mayotte index c915d90973bfbbb9ad3c7169a80cdb4f9250eab9..750d3dc14cabc52517d6be5d76da4080f213f4fc 100644 GIT binary patch literal 283 zcmWHE%1kq2zyPd35fBCe7+bgj$l3Vr)}JkhW?eWw(f!6-{fAc=7@3$E85opWKq|Ei z7+4q>lrF21A|ruNJ`6qfyKu+gu&G@1jJyt$|A7F%sa!zgb&a_Irc@M( diff --git a/lib/pytz/zoneinfo/Jamaica b/lib/pytz/zoneinfo/Jamaica index 24ea5dc09ba72f032adfdb753605764f13105849..006689bc895854db5deb33a29ff5d99c6c205fc6 100644 GIT binary patch delta 21 acmey({F`}#2{U`IkW)djLZxSogYAodKNISGBDIl zVBln6n6-g{H^A37gdxB^guyE~guw}jVITy%g+R?91Hga{$`<_r75EPXVcUWDu4iXcfW3j{GbC^|`(%cY|aA_5PZTVgM=)a;g_GN&d(hFVq>6eM(1 z7=b4ReGm-#QV@a>LG%F`2tricClW*ugiuIP_w{txQ3O5XeSh0KcC!B!w5Gdj-5+PU zJ>lZ)wTt&9r|oui-Q7anu5zuLUy|tNh(xE~N^EVF#`2}o`1qs5v->o0?WG*7c%n^b z^3t?)Lz^?twfW8HY!G~qV5V1FBG07d`guuiSkUCzv>g8NR9jOqX?u5D+xJ(?kw@d& zv8hy!PWG#;-m0DFE=cF65>0jYN$SOC?P^F!*PYkev!zCQ#_wx-WtpTim$i3cQ8K|j z>3g+C`y-cRApb>=t+$(EIkEe_j!o~8la&QMHL+3LvZ8-^Id`*Q|DKzgEn4B+t%6(C7!O>-fkWH^ zzOfVh#TMUw|HS>Y!zO%W7q4xD?BlhKke$4?6|xty8L}I)9kQR-Hbi#x+Lp+kUfUGe z)oa@#`+99-WM^b+WN&11WOrnHWPhXqqyw+Dfb`(CCXg; zH%L23KS)DJM_y|Q>B(zNAzgW`Eu=56HHLKNwbqc{kmiu?koJ)NkOuL8by#dkR)@D! VXH`5L4uwNCW~eq4*;c=!_!kUa7>57= literal 1078 zcmciAJ7`l;9LMpSS_f-YL`9H_;A7F)Hs%rwDk`Ew)95k1l-j24DIvBsK0*kkt%-_) z4x*EjkHt4A0i`I4L$IB!!x@C4bU1=Kw9rXWictUGJdDzCw%XG`@X`RULwFhs%)rZ!M zTXnvy)!coX%)YV74?)wbOkR_%*(w*5k^A9qC=FbHcZ&ed|=$ z=waQxA*6b)MYXP7YkCW-bnnc(Nw4}df6Me5UkH$=2-8b8J`JUg3ImJ+-o5<%&Hv_qAE&Gew<$7gmM+-MTQkR1I$0qX%zoHbV>7 z>!DJu8U9?YM^dxq^!OKD+-XdyTxHMHJvC>qe6n6u=wDu*_n;#Gp7+dzsy**v#aq;p z2)qN$t=s~>krVvI7C(Of#G9AHCcI@Ar)-1lYA!9{q;xe$6jI`W03H diff --git a/lib/pytz/zoneinfo/ROK b/lib/pytz/zoneinfo/ROK index 6931d782bba52a19a474013de9af78055801a4a7..fd91d5b729aaa78253bd439c36a103fe88ce33b2 100644 GIT binary patch literal 571 zcmWHE%1kq2zyRz(5fBCeaUcewSaLHNy!y|vq4^OhU|9C1a zk?|~vx#GE?&x;rO1r;xzf5~{oA5`(`__d7J?@cP+EZ>pw_PkidyY^WbA504?6c#5; zP|Qo8pw#R%LD|o90s|uxGYcat5@cZmLI#F%4xp_JkLLg z28NymjDkMCAq?KZAq-y5AOeWJT|z)Qkw6Fue*FQ}_a6vAeg@GXe}ia{-$69U{~#I^ z1|S*~4j>v779biF9v~VNCLkIVE?^oMHXs@lK42OcMj#p#P9Pc-Rv;P_ULYD2W*{0A dZXjoY!VW}(!Vg4)!VpB$D;&9i;jC-P1ptE4#?=4- literal 500 zcmWHE%1kq2zyO>;5fBCeejo<1MH_%b>*TtM4gY#S>}c6iaX8ev;F7cYhe!UJAKpHk z)bOs6^TP+ziiW>Sxqc`tb}3NIvrSNHRx42UlTTn|Vq{`wVPj=uWMKzF28MDDplJ-{ z9SlHr-2?_84@mNYNw5f`AOk}|14y=K0f-HhW%2P1Vek$PVeoPW5kTzi5&|*>4TKQ( zlK@Z)*iS#8djA7KW?M=Hhz9u)M1%YZqCtKI(IEeVXpo;lG|1l|8sv8n4e~#T2898L i289F2cu-h?Xi#{7Xi%7dXi&H?&@*7TfPtrL$prw{(u!38 diff --git a/lib/pytz/zoneinfo/zone.tab b/lib/pytz/zoneinfo/zone.tab index 084bb2fb..a7373f17 100644 --- a/lib/pytz/zoneinfo/zone.tab +++ b/lib/pytz/zoneinfo/zone.tab @@ -307,7 +307,8 @@ PE -1203-07703 America/Lima PF -1732-14934 Pacific/Tahiti Society Islands PF -0900-13930 Pacific/Marquesas Marquesas Islands PF -2308-13457 Pacific/Gambier Gambier Islands -PG -0930+14710 Pacific/Port_Moresby +PG -0930+14710 Pacific/Port_Moresby most locations +PG -0613+15534 Pacific/Bougainville Bougainville PH +1435+12100 Asia/Manila PK +2452+06703 Asia/Karachi PL +5215+02100 Europe/Warsaw diff --git a/lib/pytz/zoneinfo/zone1970.tab b/lib/pytz/zoneinfo/zone1970.tab index 03c50d89..e971bc7f 100644 --- a/lib/pytz/zoneinfo/zone1970.tab +++ b/lib/pytz/zoneinfo/zone1970.tab @@ -264,7 +264,8 @@ PE -1203-07703 America/Lima PF -1732-14934 Pacific/Tahiti Society Islands PF -0900-13930 Pacific/Marquesas Marquesas Islands PF -2308-13457 Pacific/Gambier Gambier Islands -PG -0930+14710 Pacific/Port_Moresby +PG -0930+14710 Pacific/Port_Moresby most locations +PG -0613+15534 Pacific/Bougainville Bougainville PH +1435+12100 Asia/Manila PK +2452+06703 Asia/Karachi PL +5215+02100 Europe/Warsaw @@ -315,7 +316,7 @@ SY +3330+03618 Asia/Damascus TC +2128-07108 America/Grand_Turk TD +1207+01503 Africa/Ndjamena TF -492110+0701303 Indian/Kerguelen Kerguelen, St Paul I, Amsterdam I -TH,KH,LA,VN +1345+10031 Asia/Bangkok +TH,KH,LA,VN +1345+10031 Asia/Bangkok most of Indochina TJ +3835+06848 Asia/Dushanbe TK -0922-17114 Pacific/Fakaofo TL -0833+12535 Asia/Dili @@ -323,7 +324,7 @@ TM +3757+05823 Asia/Ashgabat TN +3648+01011 Africa/Tunis TO -2110-17510 Pacific/Tongatapu TR +4101+02858 Europe/Istanbul -TT,AG,AI,BL,DM,GD,GP,MF,LC,KN,MS,VC,VG,VI +1039-06131 America/Port_of_Spain +TT,AG,AI,BL,DM,GD,GP,KN,LC,MF,MS,VC,VG,VI +1039-06131 America/Port_of_Spain TV -0831+17913 Pacific/Funafuti TW +2503+12130 Asia/Taipei UA +5026+03031 Europe/Kiev most locations @@ -363,6 +364,7 @@ UY -3453-05611 America/Montevideo UZ +3940+06648 Asia/Samarkand west Uzbekistan UZ +4120+06918 Asia/Tashkent east Uzbekistan VE +1030-06656 America/Caracas +VN +1045+10640 Asia/Ho_Chi_Minh south Vietnam VU -1740+16825 Pacific/Efate WF -1318-17610 Pacific/Wallis WS -1350-17144 Pacific/Apia