pytz-2014.10/0000775000175000017500000000000012435564151013351 5ustar jamespagejamespagepytz-2014.10/LICENSE.txt0000664000175000017500000000210012435564046015170 0ustar jamespagejamespageCopyright (c) 2003-2009 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. pytz-2014.10/pytz/0000775000175000017500000000000012470347544014363 5ustar jamespagejamespagepytz-2014.10/pytz/tests/0000775000175000017500000000000012435564151015521 5ustar jamespagejamespagepytz-2014.10/pytz/tests/test_lazy.py0000644000175000017500000002305412435564046020116 0ustar jamespagejamespagefrom 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() pytz-2014.10/pytz/tests/test_tzinfo.py0000664000175000017500000007145612435564046020463 0ustar jamespagejamespage# -*- 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.10' EXPECTED_OLSON_VERSION='2014j' 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('?'*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': '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') # 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 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') pytz-2014.10/pytz/tests/test_docs.py0000664000175000017500000000151412435564046020066 0ustar jamespagejamespage# -*- 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') pytz-2014.10/pytz/tzfile.py0000664000175000017500000001140512435564046016232 0ustar jamespagejamespage#!/usr/bin/env python ''' $Id: tzfile.py,v 1.8 2004/06/03 00:15:24 zenzen Exp $ ''' try: from cStringIO import StringIO except ImportError: from io import StringIO from datetime import datetime, timedelta from struct import unpack, calcsize from pytz.tzinfo import StaticTzInfo, DstTzInfo, memorized_ttinfo from pytz.tzinfo import memorized_datetime, memorized_timedelta def _byte_string(s): """Cast a string or byte string to an ASCII byte string.""" return s.encode('US-ASCII') _NULL = _byte_string('\0') def _std_string(s): """Cast a string or byte string to an ASCII string.""" return str(s.decode('US-ASCII')) def build_tzinfo(zone, fp): head_fmt = '>4s c 15x 6l' head_size = calcsize(head_fmt) (magic, format, ttisgmtcnt, ttisstdcnt,leapcnt, timecnt, typecnt, charcnt) = unpack(head_fmt, fp.read(head_size)) # Make sure it is a tzfile(5) file assert magic == _byte_string('TZif'), 'Got magic %s' % repr(magic) # Read out the transition times, localtime indices and ttinfo structures. data_fmt = '>%(timecnt)dl %(timecnt)dB %(ttinfo)s %(charcnt)ds' % dict( timecnt=timecnt, ttinfo='lBB'*typecnt, charcnt=charcnt) data_size = calcsize(data_fmt) data = unpack(data_fmt, fp.read(data_size)) # make sure we unpacked the right number of values assert len(data) == 2 * timecnt + 3 * typecnt + 1 transitions = [memorized_datetime(trans) for trans in data[:timecnt]] lindexes = list(data[timecnt:2 * timecnt]) ttinfo_raw = data[2 * timecnt:-1] tznames_raw = data[-1] del data # Process ttinfo into separate structs ttinfo = [] tznames = {} i = 0 while i < len(ttinfo_raw): # have we looked up this timezone name yet? tzname_offset = ttinfo_raw[i+2] if tzname_offset not in tznames: nul = tznames_raw.find(_NULL, tzname_offset) if nul < 0: nul = len(tznames_raw) tznames[tzname_offset] = _std_string( tznames_raw[tzname_offset:nul]) ttinfo.append((ttinfo_raw[i], bool(ttinfo_raw[i+1]), tznames[tzname_offset])) i += 3 # Now build the timezone object if len(transitions) == 0: ttinfo[0][0], ttinfo[0][2] cls = type(zone, (StaticTzInfo,), dict( zone=zone, _utcoffset=memorized_timedelta(ttinfo[0][0]), _tzname=ttinfo[0][2])) else: # Early dates use the first standard time ttinfo i = 0 while ttinfo[i][1]: i += 1 if ttinfo[i] == ttinfo[lindexes[0]]: transitions[0] = datetime.min else: transitions.insert(0, datetime.min) lindexes.insert(0, i) # calculate transition info transition_info = [] for i in range(len(transitions)): inf = ttinfo[lindexes[i]] utcoffset = inf[0] if not inf[1]: dst = 0 else: for j in range(i-1, -1, -1): prev_inf = ttinfo[lindexes[j]] if not prev_inf[1]: break dst = inf[0] - prev_inf[0] # dst offset # Bad dst? Look further. DST > 24 hours happens when # a timzone has moved across the international dateline. if dst <= 0 or dst > 3600*3: for j in range(i+1, len(transitions)): stdinf = ttinfo[lindexes[j]] if not stdinf[1]: dst = inf[0] - stdinf[0] if dst > 0: break # Found a useful std time. tzname = inf[2] # Round utcoffset and dst to the nearest minute or the # datetime library will complain. Conversions to these timezones # might be up to plus or minus 30 seconds out, but it is # the best we can do. utcoffset = int((utcoffset + 30) // 60) * 60 dst = int((dst + 30) // 60) * 60 transition_info.append(memorized_ttinfo(utcoffset, dst, tzname)) cls = type(zone, (DstTzInfo,), dict( zone=zone, _utc_transition_times=transitions, _transition_info=transition_info)) return cls() if __name__ == '__main__': import os.path from pprint import pprint base = os.path.join(os.path.dirname(__file__), 'zoneinfo') tz = build_tzinfo('Australia/Melbourne', open(os.path.join(base,'Australia','Melbourne'), 'rb')) tz = build_tzinfo('US/Eastern', open(os.path.join(base,'US','Eastern'), 'rb')) pprint(tz._utc_transition_times) #print tz.asPython(4) #print tz.transitions_mapping pytz-2014.10/pytz/__init__.py0000664000175000017500000010233312435564046016475 0ustar jamespagejamespage''' datetime.tzinfo timezone definitions generated from the Olson timezone database: ftp://elsie.nci.nih.gov/pub/tz*.tar.gz See the datetime section of the Python Library Reference for information on how to use these modules. ''' # The Olson database is updated several times a year. OLSON_VERSION = '2014j' VERSION = '2014.10' # Switching to pip compatible version numbering. __version__ = VERSION OLSEN_VERSION = OLSON_VERSION # Old releases had this misspelling __all__ = [ 'timezone', 'utc', 'country_timezones', 'country_names', 'AmbiguousTimeError', 'InvalidTimeError', 'NonExistentTimeError', 'UnknownTimeZoneError', 'all_timezones', 'all_timezones_set', 'common_timezones', 'common_timezones_set', ] import sys, datetime, os.path, gettext try: from pkg_resources import resource_stream except ImportError: resource_stream = None 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.tzinfo import unpickler from pytz.tzfile import build_tzinfo, _byte_string try: unicode except NameError: # Python 3.x # Python 3.x doesn't have unicode(), making writing code # for Python 2.3 and Python 3.x a pain. unicode = str def ascii(s): r""" >>> ascii('Hello') 'Hello' >>> ascii('\N{TRADE MARK SIGN}') #doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... UnicodeEncodeError: ... """ s.encode('US-ASCII') # Raise an exception if not ASCII return s # But return the original string - not a byte string. else: # Python 2.x def ascii(s): r""" >>> ascii('Hello') 'Hello' >>> ascii(u'Hello') 'Hello' >>> ascii(u'\N{TRADE MARK SIGN}') #doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... UnicodeEncodeError: ... """ return s.encode('US-ASCII') def open_resource(name): """Open a resource from the zoneinfo subdir for reading. Uses the pkg_resources module if available and no standard file found at the calculated location. """ name_parts = name.lstrip('/').split('/') for part in name_parts: if part == os.path.pardir or os.path.sep in part: raise ValueError('Bad path segment: %r' % part) filename = os.path.join(os.path.dirname(__file__), 'zoneinfo', *name_parts) if not os.path.exists(filename) and resource_stream is not None: # http://bugs.launchpad.net/bugs/383171 - we avoid using this # unless absolutely necessary to help when a broken version of # pkg_resources is installed. return resource_stream(__name__, 'zoneinfo/' + name) return open(filename, 'rb') def resource_exists(name): """Return true if the given resource exists""" try: open_resource(name).close() return True except IOError: return False # Enable this when we get some translations? # We want an i18n API that is useful to programs using Python's gettext # module, as well as the Zope3 i18n package. Perhaps we should just provide # the POT file and translations, and leave it up to callers to make use # of them. # # t = gettext.translation( # 'pytz', os.path.join(os.path.dirname(__file__), 'locales'), # fallback=True # ) # def _(timezone_name): # """Translate a timezone name using the current locale, returning Unicode""" # return t.ugettext(timezone_name) _tzinfo_cache = {} def timezone(zone): r''' Return a datetime.tzinfo implementation for the given timezone >>> from datetime import datetime, timedelta >>> utc = timezone('UTC') >>> eastern = timezone('US/Eastern') >>> eastern.zone 'US/Eastern' >>> timezone(unicode('US/Eastern')) is eastern True >>> utc_dt = datetime(2002, 10, 27, 6, 0, 0, tzinfo=utc) >>> loc_dt = utc_dt.astimezone(eastern) >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)' >>> loc_dt.strftime(fmt) '2002-10-27 01:00:00 EST (-0500)' >>> (loc_dt - timedelta(minutes=10)).strftime(fmt) '2002-10-27 00:50:00 EST (-0500)' >>> eastern.normalize(loc_dt - timedelta(minutes=10)).strftime(fmt) '2002-10-27 01:50:00 EDT (-0400)' >>> (loc_dt + timedelta(minutes=10)).strftime(fmt) '2002-10-27 01:10:00 EST (-0500)' Raises UnknownTimeZoneError if passed an unknown zone. >>> try: ... timezone('Asia/Shangri-La') ... except UnknownTimeZoneError: ... print('Unknown') Unknown >>> try: ... timezone(unicode('\N{TRADE MARK SIGN}')) ... except UnknownTimeZoneError: ... print('Unknown') Unknown ''' if zone.upper() == 'UTC': return utc try: zone = ascii(zone) except UnicodeEncodeError: # All valid timezones are ASCII raise UnknownTimeZoneError(zone) zone = _unmunge_zone(zone) if zone not in _tzinfo_cache: if zone in all_timezones_set: fp = open_resource(zone) try: _tzinfo_cache[zone] = build_tzinfo(zone, fp) finally: fp.close() else: raise UnknownTimeZoneError(zone) return _tzinfo_cache[zone] def _unmunge_zone(zone): """Undo the time zone name munging done by older versions of pytz.""" return zone.replace('_plus_', '+').replace('_minus_', '-') ZERO = datetime.timedelta(0) HOUR = datetime.timedelta(hours=1) class UTC(datetime.tzinfo): """UTC Optimized UTC implementation. It unpickles using the single module global instance defined beneath this class declaration. """ zone = "UTC" _utcoffset = ZERO _dst = ZERO _tzname = zone def fromutc(self, dt): if dt.tzinfo is None: return self.localize(dt) return super(utc.__class__, self).fromutc(dt) def utcoffset(self, dt): return ZERO def tzname(self, dt): return "UTC" def dst(self, dt): return ZERO def __reduce__(self): return _UTC, () def localize(self, dt, is_dst=False): '''Convert naive time to local time''' if dt.tzinfo is not None: raise ValueError('Not naive datetime (tzinfo is already set)') return dt.replace(tzinfo=self) def normalize(self, dt, is_dst=False): '''Correct the timezone information on the given datetime''' if dt.tzinfo is self: return dt if dt.tzinfo is None: raise ValueError('Naive time - no tzinfo set') return dt.astimezone(self) def __repr__(self): return "" def __str__(self): return "UTC" UTC = utc = UTC() # UTC is a singleton def _UTC(): """Factory function for utc unpickling. Makes sure that unpickling a utc instance always returns the same module global. These examples belong in the UTC class above, but it is obscured; or in the README.txt, but we are not depending on Python 2.4 so integrating the README.txt examples with the unit tests is not trivial. >>> import datetime, pickle >>> dt = datetime.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 >>> utc is UTC is timezone('UTC') True >>> utc is timezone('GMT') False """ return utc _UTC.__safe_for_unpickling__ = True def _p(*args): """Factory function for unpickling pytz tzinfo instances. Just a wrapper around tzinfo.unpickler to save a few bytes in each pickle by shortening the path. """ return unpickler(*args) _p.__safe_for_unpickling__ = True class _CountryTimezoneDict(LazyDict): """Map ISO 3166 country code to a list of timezone names commonly used in that country. iso3166_code is the two letter code used to identify the country. >>> def print_list(list_of_strings): ... 'We use a helper so doctests work under Python 2.3 -> 3.x' ... for s in list_of_strings: ... print(s) >>> print_list(country_timezones['nz']) Pacific/Auckland Pacific/Chatham >>> print_list(country_timezones['ch']) Europe/Zurich >>> print_list(country_timezones['CH']) Europe/Zurich >>> print_list(country_timezones[unicode('ch')]) Europe/Zurich >>> print_list(country_timezones['XXX']) Traceback (most recent call last): ... KeyError: 'XXX' Previously, this information was exposed as a function rather than a dictionary. This is still supported:: >>> print_list(country_timezones('nz')) Pacific/Auckland Pacific/Chatham """ def __call__(self, iso3166_code): """Backwards compatibility.""" return self[iso3166_code] def _fill(self): data = {} zone_tab = open_resource('zone.tab') try: for line in zone_tab: line = line.decode('US-ASCII') if line.startswith('#'): continue code, coordinates, zone = line.split(None, 4)[:3] if zone not in all_timezones_set: continue try: data[code].append(zone) except KeyError: data[code] = [zone] self.data = data finally: zone_tab.close() country_timezones = _CountryTimezoneDict() class _CountryNameDict(LazyDict): '''Dictionary proving ISO3166 code -> English name. >>> print(country_names['au']) Australia ''' def _fill(self): data = {} zone_tab = open_resource('iso3166.tab') try: for line in zone_tab.readlines(): line = line.decode('US-ASCII') if line.startswith('#'): continue code, name = line.split(None, 1) data[code] = name.strip() self.data = data finally: zone_tab.close() country_names = _CountryNameDict() # Time-zone info based solely on fixed offsets class _FixedOffset(datetime.tzinfo): zone = None # to match the standard pytz API def __init__(self, minutes): if abs(minutes) >= 1440: raise ValueError("absolute offset is too large", minutes) self._minutes = minutes self._offset = datetime.timedelta(minutes=minutes) def utcoffset(self, dt): return self._offset def __reduce__(self): return FixedOffset, (self._minutes, ) def dst(self, dt): return ZERO def tzname(self, dt): return None def __repr__(self): return 'pytz.FixedOffset(%d)' % self._minutes def localize(self, dt, is_dst=False): '''Convert naive time to local time''' if dt.tzinfo is not None: raise ValueError('Not naive datetime (tzinfo is already set)') return dt.replace(tzinfo=self) def normalize(self, dt, is_dst=False): '''Correct the timezone information on the given datetime''' if dt.tzinfo is None: raise ValueError('Naive time - no tzinfo set') return dt.replace(tzinfo=self) def FixedOffset(offset, _tzinfos = {}): """return a fixed-offset timezone based off a number of minutes. >>> one = FixedOffset(-330) >>> one pytz.FixedOffset(-330) >>> one.utcoffset(datetime.datetime.now()) datetime.timedelta(-1, 66600) >>> one.dst(datetime.datetime.now()) datetime.timedelta(0) >>> two = FixedOffset(1380) >>> two pytz.FixedOffset(1380) >>> two.utcoffset(datetime.datetime.now()) datetime.timedelta(0, 82800) >>> two.dst(datetime.datetime.now()) datetime.timedelta(0) The datetime.timedelta must be between the range of -1 and 1 day, non-inclusive. >>> FixedOffset(1440) Traceback (most recent call last): ... ValueError: ('absolute offset is too large', 1440) >>> FixedOffset(-1440) Traceback (most recent call last): ... ValueError: ('absolute offset is too large', -1440) An offset of 0 is special-cased to return UTC. >>> FixedOffset(0) is UTC True There should always be only one instance of a FixedOffset per timedelta. This should be true for multiple creation calls. >>> FixedOffset(-330) is one True >>> FixedOffset(1380) is two True It should also be true for pickling. >>> import pickle >>> pickle.loads(pickle.dumps(one)) is one True >>> pickle.loads(pickle.dumps(two)) is two True """ if offset == 0: return UTC info = _tzinfos.get(offset) if info is None: # We haven't seen this one before. we need to save it. # Use setdefault to avoid a race condition and make sure we have # only one info = _tzinfos.setdefault(offset, _FixedOffset(offset)) return info FixedOffset.__safe_for_unpickling__ = True def _test(): import doctest, os, sys sys.path.insert(0, os.pardir) import pytz return doctest.testmod(pytz) if __name__ == '__main__': _test() all_timezones = \ ['Africa/Abidjan', 'Africa/Accra', 'Africa/Addis_Ababa', 'Africa/Algiers', 'Africa/Asmara', 'Africa/Asmera', 'Africa/Bamako', 'Africa/Bangui', 'Africa/Banjul', 'Africa/Bissau', 'Africa/Blantyre', 'Africa/Brazzaville', 'Africa/Bujumbura', 'Africa/Cairo', 'Africa/Casablanca', 'Africa/Ceuta', 'Africa/Conakry', 'Africa/Dakar', 'Africa/Dar_es_Salaam', 'Africa/Djibouti', 'Africa/Douala', 'Africa/El_Aaiun', 'Africa/Freetown', 'Africa/Gaborone', 'Africa/Harare', 'Africa/Johannesburg', 'Africa/Juba', 'Africa/Kampala', 'Africa/Khartoum', 'Africa/Kigali', 'Africa/Kinshasa', 'Africa/Lagos', 'Africa/Libreville', 'Africa/Lome', 'Africa/Luanda', 'Africa/Lubumbashi', 'Africa/Lusaka', 'Africa/Malabo', 'Africa/Maputo', 'Africa/Maseru', 'Africa/Mbabane', 'Africa/Mogadishu', 'Africa/Monrovia', 'Africa/Nairobi', 'Africa/Ndjamena', 'Africa/Niamey', 'Africa/Nouakchott', 'Africa/Ouagadougou', 'Africa/Porto-Novo', 'Africa/Sao_Tome', 'Africa/Timbuktu', 'Africa/Tripoli', 'Africa/Tunis', 'Africa/Windhoek', 'America/Adak', 'America/Anchorage', 'America/Anguilla', 'America/Antigua', 'America/Araguaina', 'America/Argentina/Buenos_Aires', 'America/Argentina/Catamarca', 'America/Argentina/ComodRivadavia', 'America/Argentina/Cordoba', 'America/Argentina/Jujuy', 'America/Argentina/La_Rioja', 'America/Argentina/Mendoza', 'America/Argentina/Rio_Gallegos', 'America/Argentina/Salta', 'America/Argentina/San_Juan', 'America/Argentina/San_Luis', 'America/Argentina/Tucuman', 'America/Argentina/Ushuaia', 'America/Aruba', 'America/Asuncion', 'America/Atikokan', 'America/Atka', 'America/Bahia', 'America/Bahia_Banderas', 'America/Barbados', 'America/Belem', 'America/Belize', 'America/Blanc-Sablon', 'America/Boa_Vista', 'America/Bogota', 'America/Boise', 'America/Buenos_Aires', 'America/Cambridge_Bay', 'America/Campo_Grande', 'America/Cancun', 'America/Caracas', 'America/Catamarca', 'America/Cayenne', 'America/Cayman', 'America/Chicago', 'America/Chihuahua', 'America/Coral_Harbour', 'America/Cordoba', 'America/Costa_Rica', 'America/Creston', 'America/Cuiaba', 'America/Curacao', 'America/Danmarkshavn', 'America/Dawson', 'America/Dawson_Creek', 'America/Denver', 'America/Detroit', 'America/Dominica', 'America/Edmonton', 'America/Eirunepe', 'America/El_Salvador', 'America/Ensenada', 'America/Fort_Wayne', 'America/Fortaleza', 'America/Glace_Bay', 'America/Godthab', 'America/Goose_Bay', 'America/Grand_Turk', 'America/Grenada', 'America/Guadeloupe', 'America/Guatemala', 'America/Guayaquil', 'America/Guyana', 'America/Halifax', 'America/Havana', 'America/Hermosillo', 'America/Indiana/Indianapolis', 'America/Indiana/Knox', 'America/Indiana/Marengo', 'America/Indiana/Petersburg', 'America/Indiana/Tell_City', 'America/Indiana/Vevay', 'America/Indiana/Vincennes', 'America/Indiana/Winamac', 'America/Indianapolis', 'America/Inuvik', 'America/Iqaluit', 'America/Jamaica', 'America/Jujuy', 'America/Juneau', 'America/Kentucky/Louisville', 'America/Kentucky/Monticello', 'America/Knox_IN', 'America/Kralendijk', 'America/La_Paz', 'America/Lima', 'America/Los_Angeles', 'America/Louisville', 'America/Lower_Princes', 'America/Maceio', 'America/Managua', 'America/Manaus', 'America/Marigot', 'America/Martinique', 'America/Matamoros', 'America/Mazatlan', 'America/Mendoza', 'America/Menominee', 'America/Merida', 'America/Metlakatla', 'America/Mexico_City', 'America/Miquelon', 'America/Moncton', 'America/Monterrey', 'America/Montevideo', 'America/Montreal', 'America/Montserrat', 'America/Nassau', 'America/New_York', 'America/Nipigon', 'America/Nome', 'America/Noronha', 'America/North_Dakota/Beulah', 'America/North_Dakota/Center', 'America/North_Dakota/New_Salem', 'America/Ojinaga', 'America/Panama', 'America/Pangnirtung', 'America/Paramaribo', 'America/Phoenix', 'America/Port-au-Prince', 'America/Port_of_Spain', 'America/Porto_Acre', 'America/Porto_Velho', 'America/Puerto_Rico', 'America/Rainy_River', 'America/Rankin_Inlet', 'America/Recife', 'America/Regina', 'America/Resolute', 'America/Rio_Branco', 'America/Rosario', 'America/Santa_Isabel', 'America/Santarem', 'America/Santiago', 'America/Santo_Domingo', 'America/Sao_Paulo', 'America/Scoresbysund', 'America/Shiprock', 'America/Sitka', 'America/St_Barthelemy', 'America/St_Johns', 'America/St_Kitts', 'America/St_Lucia', 'America/St_Thomas', 'America/St_Vincent', 'America/Swift_Current', 'America/Tegucigalpa', 'America/Thule', 'America/Thunder_Bay', 'America/Tijuana', 'America/Toronto', 'America/Tortola', 'America/Vancouver', 'America/Virgin', 'America/Whitehorse', 'America/Winnipeg', 'America/Yakutat', 'America/Yellowknife', 'Antarctica/Casey', 'Antarctica/Davis', 'Antarctica/DumontDUrville', 'Antarctica/Macquarie', 'Antarctica/Mawson', 'Antarctica/McMurdo', 'Antarctica/Palmer', 'Antarctica/Rothera', 'Antarctica/South_Pole', 'Antarctica/Syowa', 'Antarctica/Troll', 'Antarctica/Vostok', 'Arctic/Longyearbyen', 'Asia/Aden', 'Asia/Almaty', 'Asia/Amman', 'Asia/Anadyr', 'Asia/Aqtau', 'Asia/Aqtobe', 'Asia/Ashgabat', 'Asia/Ashkhabad', 'Asia/Baghdad', 'Asia/Bahrain', 'Asia/Baku', 'Asia/Bangkok', 'Asia/Beirut', 'Asia/Bishkek', 'Asia/Brunei', 'Asia/Calcutta', 'Asia/Chita', 'Asia/Choibalsan', 'Asia/Chongqing', 'Asia/Chungking', 'Asia/Colombo', 'Asia/Dacca', 'Asia/Damascus', 'Asia/Dhaka', 'Asia/Dili', 'Asia/Dubai', 'Asia/Dushanbe', 'Asia/Gaza', 'Asia/Harbin', 'Asia/Hebron', 'Asia/Ho_Chi_Minh', 'Asia/Hong_Kong', 'Asia/Hovd', 'Asia/Irkutsk', 'Asia/Istanbul', 'Asia/Jakarta', 'Asia/Jayapura', 'Asia/Jerusalem', 'Asia/Kabul', 'Asia/Kamchatka', 'Asia/Karachi', 'Asia/Kashgar', 'Asia/Kathmandu', 'Asia/Katmandu', 'Asia/Khandyga', 'Asia/Kolkata', 'Asia/Krasnoyarsk', 'Asia/Kuala_Lumpur', 'Asia/Kuching', 'Asia/Kuwait', 'Asia/Macao', 'Asia/Macau', 'Asia/Magadan', 'Asia/Makassar', 'Asia/Manila', 'Asia/Muscat', 'Asia/Nicosia', 'Asia/Novokuznetsk', 'Asia/Novosibirsk', 'Asia/Omsk', 'Asia/Oral', 'Asia/Phnom_Penh', 'Asia/Pontianak', 'Asia/Pyongyang', 'Asia/Qatar', 'Asia/Qyzylorda', 'Asia/Rangoon', 'Asia/Riyadh', 'Asia/Saigon', 'Asia/Sakhalin', 'Asia/Samarkand', 'Asia/Seoul', 'Asia/Shanghai', 'Asia/Singapore', 'Asia/Srednekolymsk', 'Asia/Taipei', 'Asia/Tashkent', 'Asia/Tbilisi', 'Asia/Tehran', 'Asia/Tel_Aviv', 'Asia/Thimbu', 'Asia/Thimphu', 'Asia/Tokyo', 'Asia/Ujung_Pandang', 'Asia/Ulaanbaatar', 'Asia/Ulan_Bator', 'Asia/Urumqi', 'Asia/Ust-Nera', 'Asia/Vientiane', 'Asia/Vladivostok', 'Asia/Yakutsk', 'Asia/Yekaterinburg', 'Asia/Yerevan', 'Atlantic/Azores', 'Atlantic/Bermuda', 'Atlantic/Canary', 'Atlantic/Cape_Verde', 'Atlantic/Faeroe', 'Atlantic/Faroe', 'Atlantic/Jan_Mayen', 'Atlantic/Madeira', 'Atlantic/Reykjavik', 'Atlantic/South_Georgia', 'Atlantic/St_Helena', 'Atlantic/Stanley', 'Australia/ACT', 'Australia/Adelaide', 'Australia/Brisbane', 'Australia/Broken_Hill', 'Australia/Canberra', 'Australia/Currie', 'Australia/Darwin', 'Australia/Eucla', 'Australia/Hobart', 'Australia/LHI', 'Australia/Lindeman', 'Australia/Lord_Howe', 'Australia/Melbourne', 'Australia/NSW', 'Australia/North', 'Australia/Perth', 'Australia/Queensland', 'Australia/South', 'Australia/Sydney', 'Australia/Tasmania', 'Australia/Victoria', 'Australia/West', 'Australia/Yancowinna', 'Brazil/Acre', 'Brazil/DeNoronha', 'Brazil/East', 'Brazil/West', 'CET', 'CST6CDT', 'Canada/Atlantic', 'Canada/Central', 'Canada/East-Saskatchewan', 'Canada/Eastern', 'Canada/Mountain', 'Canada/Newfoundland', 'Canada/Pacific', 'Canada/Saskatchewan', 'Canada/Yukon', 'Chile/Continental', 'Chile/EasterIsland', 'Cuba', 'EET', 'EST', 'EST5EDT', 'Egypt', 'Eire', 'Etc/GMT', 'Etc/GMT+0', 'Etc/GMT+1', 'Etc/GMT+10', 'Etc/GMT+11', 'Etc/GMT+12', 'Etc/GMT+2', 'Etc/GMT+3', 'Etc/GMT+4', 'Etc/GMT+5', 'Etc/GMT+6', 'Etc/GMT+7', 'Etc/GMT+8', 'Etc/GMT+9', 'Etc/GMT-0', 'Etc/GMT-1', 'Etc/GMT-10', 'Etc/GMT-11', 'Etc/GMT-12', 'Etc/GMT-13', 'Etc/GMT-14', 'Etc/GMT-2', 'Etc/GMT-3', 'Etc/GMT-4', 'Etc/GMT-5', 'Etc/GMT-6', 'Etc/GMT-7', 'Etc/GMT-8', 'Etc/GMT-9', 'Etc/GMT0', 'Etc/Greenwich', 'Etc/UCT', 'Etc/UTC', 'Etc/Universal', 'Etc/Zulu', 'Europe/Amsterdam', 'Europe/Andorra', 'Europe/Athens', 'Europe/Belfast', 'Europe/Belgrade', 'Europe/Berlin', 'Europe/Bratislava', 'Europe/Brussels', 'Europe/Bucharest', 'Europe/Budapest', 'Europe/Busingen', 'Europe/Chisinau', 'Europe/Copenhagen', 'Europe/Dublin', 'Europe/Gibraltar', 'Europe/Guernsey', 'Europe/Helsinki', 'Europe/Isle_of_Man', 'Europe/Istanbul', 'Europe/Jersey', 'Europe/Kaliningrad', 'Europe/Kiev', 'Europe/Lisbon', 'Europe/Ljubljana', 'Europe/London', 'Europe/Luxembourg', 'Europe/Madrid', 'Europe/Malta', 'Europe/Mariehamn', 'Europe/Minsk', 'Europe/Monaco', 'Europe/Moscow', 'Europe/Nicosia', 'Europe/Oslo', 'Europe/Paris', 'Europe/Podgorica', 'Europe/Prague', 'Europe/Riga', 'Europe/Rome', 'Europe/Samara', 'Europe/San_Marino', 'Europe/Sarajevo', 'Europe/Simferopol', 'Europe/Skopje', 'Europe/Sofia', 'Europe/Stockholm', 'Europe/Tallinn', 'Europe/Tirane', 'Europe/Tiraspol', 'Europe/Uzhgorod', 'Europe/Vaduz', 'Europe/Vatican', 'Europe/Vienna', 'Europe/Vilnius', 'Europe/Volgograd', 'Europe/Warsaw', 'Europe/Zagreb', 'Europe/Zaporozhye', 'Europe/Zurich', 'GB', 'GB-Eire', 'GMT', 'GMT+0', 'GMT-0', 'GMT0', 'Greenwich', 'HST', 'Hongkong', 'Iceland', 'Indian/Antananarivo', 'Indian/Chagos', 'Indian/Christmas', 'Indian/Cocos', 'Indian/Comoro', 'Indian/Kerguelen', 'Indian/Mahe', 'Indian/Maldives', 'Indian/Mauritius', 'Indian/Mayotte', 'Indian/Reunion', 'Iran', 'Israel', 'Jamaica', 'Japan', 'Kwajalein', 'Libya', 'MET', 'MST', 'MST7MDT', 'Mexico/BajaNorte', 'Mexico/BajaSur', 'Mexico/General', 'NZ', 'NZ-CHAT', 'Navajo', 'PRC', 'PST8PDT', 'Pacific/Apia', 'Pacific/Auckland', 'Pacific/Bougainville', 'Pacific/Chatham', 'Pacific/Chuuk', 'Pacific/Easter', 'Pacific/Efate', 'Pacific/Enderbury', 'Pacific/Fakaofo', 'Pacific/Fiji', 'Pacific/Funafuti', 'Pacific/Galapagos', 'Pacific/Gambier', 'Pacific/Guadalcanal', 'Pacific/Guam', 'Pacific/Honolulu', 'Pacific/Johnston', 'Pacific/Kiritimati', 'Pacific/Kosrae', 'Pacific/Kwajalein', 'Pacific/Majuro', 'Pacific/Marquesas', 'Pacific/Midway', 'Pacific/Nauru', 'Pacific/Niue', 'Pacific/Norfolk', 'Pacific/Noumea', 'Pacific/Pago_Pago', 'Pacific/Palau', 'Pacific/Pitcairn', 'Pacific/Pohnpei', 'Pacific/Ponape', 'Pacific/Port_Moresby', 'Pacific/Rarotonga', 'Pacific/Saipan', 'Pacific/Samoa', 'Pacific/Tahiti', 'Pacific/Tarawa', 'Pacific/Tongatapu', 'Pacific/Truk', 'Pacific/Wake', 'Pacific/Wallis', 'Pacific/Yap', 'Poland', 'Portugal', 'ROC', 'ROK', 'Singapore', 'Turkey', 'UCT', 'US/Alaska', 'US/Aleutian', 'US/Arizona', 'US/Central', 'US/East-Indiana', 'US/Eastern', 'US/Hawaii', 'US/Indiana-Starke', 'US/Michigan', 'US/Mountain', 'US/Pacific', 'US/Pacific-New', 'US/Samoa', 'UTC', 'Universal', 'W-SU', 'WET', 'Zulu'] all_timezones = LazyList( tz for tz in all_timezones if resource_exists(tz)) all_timezones_set = LazySet(all_timezones) common_timezones = \ ['Africa/Abidjan', 'Africa/Accra', 'Africa/Addis_Ababa', 'Africa/Algiers', 'Africa/Asmara', 'Africa/Bamako', 'Africa/Bangui', 'Africa/Banjul', 'Africa/Bissau', 'Africa/Blantyre', 'Africa/Brazzaville', 'Africa/Bujumbura', 'Africa/Cairo', 'Africa/Casablanca', 'Africa/Ceuta', 'Africa/Conakry', 'Africa/Dakar', 'Africa/Dar_es_Salaam', 'Africa/Djibouti', 'Africa/Douala', 'Africa/El_Aaiun', 'Africa/Freetown', 'Africa/Gaborone', 'Africa/Harare', 'Africa/Johannesburg', 'Africa/Juba', 'Africa/Kampala', 'Africa/Khartoum', 'Africa/Kigali', 'Africa/Kinshasa', 'Africa/Lagos', 'Africa/Libreville', 'Africa/Lome', 'Africa/Luanda', 'Africa/Lubumbashi', 'Africa/Lusaka', 'Africa/Malabo', 'Africa/Maputo', 'Africa/Maseru', 'Africa/Mbabane', 'Africa/Mogadishu', 'Africa/Monrovia', 'Africa/Nairobi', 'Africa/Ndjamena', 'Africa/Niamey', 'Africa/Nouakchott', 'Africa/Ouagadougou', 'Africa/Porto-Novo', 'Africa/Sao_Tome', 'Africa/Tripoli', 'Africa/Tunis', 'Africa/Windhoek', 'America/Adak', 'America/Anchorage', 'America/Anguilla', 'America/Antigua', 'America/Araguaina', 'America/Argentina/Buenos_Aires', 'America/Argentina/Catamarca', 'America/Argentina/Cordoba', 'America/Argentina/Jujuy', 'America/Argentina/La_Rioja', 'America/Argentina/Mendoza', 'America/Argentina/Rio_Gallegos', 'America/Argentina/Salta', 'America/Argentina/San_Juan', 'America/Argentina/San_Luis', 'America/Argentina/Tucuman', 'America/Argentina/Ushuaia', 'America/Aruba', 'America/Asuncion', 'America/Atikokan', 'America/Bahia', 'America/Bahia_Banderas', 'America/Barbados', 'America/Belem', 'America/Belize', 'America/Blanc-Sablon', 'America/Boa_Vista', 'America/Bogota', 'America/Boise', 'America/Cambridge_Bay', 'America/Campo_Grande', 'America/Cancun', 'America/Caracas', 'America/Cayenne', 'America/Cayman', 'America/Chicago', 'America/Chihuahua', 'America/Costa_Rica', 'America/Creston', 'America/Cuiaba', 'America/Curacao', 'America/Danmarkshavn', 'America/Dawson', 'America/Dawson_Creek', 'America/Denver', 'America/Detroit', 'America/Dominica', 'America/Edmonton', 'America/Eirunepe', 'America/El_Salvador', 'America/Fortaleza', 'America/Glace_Bay', 'America/Godthab', 'America/Goose_Bay', 'America/Grand_Turk', 'America/Grenada', 'America/Guadeloupe', 'America/Guatemala', 'America/Guayaquil', 'America/Guyana', 'America/Halifax', 'America/Havana', 'America/Hermosillo', 'America/Indiana/Indianapolis', 'America/Indiana/Knox', 'America/Indiana/Marengo', 'America/Indiana/Petersburg', 'America/Indiana/Tell_City', 'America/Indiana/Vevay', 'America/Indiana/Vincennes', 'America/Indiana/Winamac', 'America/Inuvik', 'America/Iqaluit', 'America/Jamaica', 'America/Juneau', 'America/Kentucky/Louisville', 'America/Kentucky/Monticello', 'America/Kralendijk', 'America/La_Paz', 'America/Lima', 'America/Los_Angeles', 'America/Lower_Princes', 'America/Maceio', 'America/Managua', 'America/Manaus', 'America/Marigot', 'America/Martinique', 'America/Matamoros', 'America/Mazatlan', 'America/Menominee', 'America/Merida', 'America/Metlakatla', 'America/Mexico_City', 'America/Miquelon', 'America/Moncton', 'America/Monterrey', 'America/Montevideo', 'America/Montreal', 'America/Montserrat', 'America/Nassau', 'America/New_York', 'America/Nipigon', 'America/Nome', 'America/Noronha', 'America/North_Dakota/Beulah', 'America/North_Dakota/Center', 'America/North_Dakota/New_Salem', 'America/Ojinaga', 'America/Panama', 'America/Pangnirtung', 'America/Paramaribo', 'America/Phoenix', 'America/Port-au-Prince', 'America/Port_of_Spain', 'America/Porto_Velho', 'America/Puerto_Rico', 'America/Rainy_River', 'America/Rankin_Inlet', 'America/Recife', 'America/Regina', 'America/Resolute', 'America/Rio_Branco', 'America/Santa_Isabel', 'America/Santarem', 'America/Santiago', 'America/Santo_Domingo', 'America/Sao_Paulo', 'America/Scoresbysund', 'America/Sitka', 'America/St_Barthelemy', 'America/St_Johns', 'America/St_Kitts', 'America/St_Lucia', 'America/St_Thomas', 'America/St_Vincent', 'America/Swift_Current', 'America/Tegucigalpa', 'America/Thule', 'America/Thunder_Bay', 'America/Tijuana', 'America/Toronto', 'America/Tortola', 'America/Vancouver', 'America/Whitehorse', 'America/Winnipeg', 'America/Yakutat', 'America/Yellowknife', 'Antarctica/Casey', 'Antarctica/Davis', 'Antarctica/DumontDUrville', 'Antarctica/Macquarie', 'Antarctica/Mawson', 'Antarctica/McMurdo', 'Antarctica/Palmer', 'Antarctica/Rothera', 'Antarctica/Syowa', 'Antarctica/Troll', 'Antarctica/Vostok', 'Arctic/Longyearbyen', 'Asia/Aden', 'Asia/Almaty', 'Asia/Amman', 'Asia/Anadyr', 'Asia/Aqtau', 'Asia/Aqtobe', 'Asia/Ashgabat', 'Asia/Baghdad', 'Asia/Bahrain', 'Asia/Baku', 'Asia/Bangkok', 'Asia/Beirut', 'Asia/Bishkek', 'Asia/Brunei', 'Asia/Chita', 'Asia/Choibalsan', 'Asia/Colombo', 'Asia/Damascus', 'Asia/Dhaka', 'Asia/Dili', 'Asia/Dubai', 'Asia/Dushanbe', 'Asia/Gaza', 'Asia/Hebron', 'Asia/Ho_Chi_Minh', 'Asia/Hong_Kong', 'Asia/Hovd', 'Asia/Irkutsk', 'Asia/Jakarta', 'Asia/Jayapura', 'Asia/Jerusalem', 'Asia/Kabul', 'Asia/Kamchatka', 'Asia/Karachi', 'Asia/Kathmandu', 'Asia/Khandyga', 'Asia/Kolkata', 'Asia/Krasnoyarsk', 'Asia/Kuala_Lumpur', 'Asia/Kuching', 'Asia/Kuwait', 'Asia/Macau', 'Asia/Magadan', 'Asia/Makassar', 'Asia/Manila', 'Asia/Muscat', 'Asia/Nicosia', 'Asia/Novokuznetsk', 'Asia/Novosibirsk', 'Asia/Omsk', 'Asia/Oral', 'Asia/Phnom_Penh', 'Asia/Pontianak', 'Asia/Pyongyang', 'Asia/Qatar', 'Asia/Qyzylorda', 'Asia/Rangoon', 'Asia/Riyadh', 'Asia/Sakhalin', 'Asia/Samarkand', 'Asia/Seoul', 'Asia/Shanghai', 'Asia/Singapore', 'Asia/Srednekolymsk', 'Asia/Taipei', 'Asia/Tashkent', 'Asia/Tbilisi', 'Asia/Tehran', 'Asia/Thimphu', 'Asia/Tokyo', 'Asia/Ulaanbaatar', 'Asia/Urumqi', 'Asia/Ust-Nera', 'Asia/Vientiane', 'Asia/Vladivostok', 'Asia/Yakutsk', 'Asia/Yekaterinburg', 'Asia/Yerevan', 'Atlantic/Azores', 'Atlantic/Bermuda', 'Atlantic/Canary', 'Atlantic/Cape_Verde', 'Atlantic/Faroe', 'Atlantic/Madeira', 'Atlantic/Reykjavik', 'Atlantic/South_Georgia', 'Atlantic/St_Helena', 'Atlantic/Stanley', 'Australia/Adelaide', 'Australia/Brisbane', 'Australia/Broken_Hill', 'Australia/Currie', 'Australia/Darwin', 'Australia/Eucla', 'Australia/Hobart', 'Australia/Lindeman', 'Australia/Lord_Howe', 'Australia/Melbourne', 'Australia/Perth', 'Australia/Sydney', 'Canada/Atlantic', 'Canada/Central', 'Canada/Eastern', 'Canada/Mountain', 'Canada/Newfoundland', 'Canada/Pacific', 'Europe/Amsterdam', 'Europe/Andorra', 'Europe/Athens', 'Europe/Belgrade', 'Europe/Berlin', 'Europe/Bratislava', 'Europe/Brussels', 'Europe/Bucharest', 'Europe/Budapest', 'Europe/Busingen', 'Europe/Chisinau', 'Europe/Copenhagen', 'Europe/Dublin', 'Europe/Gibraltar', 'Europe/Guernsey', 'Europe/Helsinki', 'Europe/Isle_of_Man', 'Europe/Istanbul', 'Europe/Jersey', 'Europe/Kaliningrad', 'Europe/Kiev', 'Europe/Lisbon', 'Europe/Ljubljana', 'Europe/London', 'Europe/Luxembourg', 'Europe/Madrid', 'Europe/Malta', 'Europe/Mariehamn', 'Europe/Minsk', 'Europe/Monaco', 'Europe/Moscow', 'Europe/Oslo', 'Europe/Paris', 'Europe/Podgorica', 'Europe/Prague', 'Europe/Riga', 'Europe/Rome', 'Europe/Samara', 'Europe/San_Marino', 'Europe/Sarajevo', 'Europe/Simferopol', 'Europe/Skopje', 'Europe/Sofia', 'Europe/Stockholm', 'Europe/Tallinn', 'Europe/Tirane', 'Europe/Uzhgorod', 'Europe/Vaduz', 'Europe/Vatican', 'Europe/Vienna', 'Europe/Vilnius', 'Europe/Volgograd', 'Europe/Warsaw', 'Europe/Zagreb', 'Europe/Zaporozhye', 'Europe/Zurich', 'GMT', 'Indian/Antananarivo', 'Indian/Chagos', 'Indian/Christmas', 'Indian/Cocos', 'Indian/Comoro', 'Indian/Kerguelen', 'Indian/Mahe', 'Indian/Maldives', 'Indian/Mauritius', 'Indian/Mayotte', 'Indian/Reunion', 'Pacific/Apia', 'Pacific/Auckland', 'Pacific/Bougainville', 'Pacific/Chatham', 'Pacific/Chuuk', 'Pacific/Easter', 'Pacific/Efate', 'Pacific/Enderbury', 'Pacific/Fakaofo', 'Pacific/Fiji', 'Pacific/Funafuti', 'Pacific/Galapagos', 'Pacific/Gambier', 'Pacific/Guadalcanal', 'Pacific/Guam', 'Pacific/Honolulu', 'Pacific/Johnston', 'Pacific/Kiritimati', 'Pacific/Kosrae', 'Pacific/Kwajalein', 'Pacific/Majuro', 'Pacific/Marquesas', 'Pacific/Midway', 'Pacific/Nauru', 'Pacific/Niue', 'Pacific/Norfolk', 'Pacific/Noumea', 'Pacific/Pago_Pago', 'Pacific/Palau', 'Pacific/Pitcairn', 'Pacific/Pohnpei', 'Pacific/Port_Moresby', 'Pacific/Rarotonga', 'Pacific/Saipan', 'Pacific/Tahiti', 'Pacific/Tarawa', 'Pacific/Tongatapu', 'Pacific/Wake', 'Pacific/Wallis', 'US/Alaska', 'US/Arizona', 'US/Central', 'US/Eastern', 'US/Hawaii', 'US/Mountain', 'US/Pacific', 'UTC'] common_timezones = LazyList( tz for tz in common_timezones if tz in all_timezones) common_timezones_set = LazySet(common_timezones) pytz-2014.10/pytz/exceptions.py0000664000175000017500000000246512435564046017124 0ustar jamespagejamespage''' Custom exceptions raised by pytz. ''' __all__ = [ 'UnknownTimeZoneError', 'InvalidTimeError', 'AmbiguousTimeError', 'NonExistentTimeError', ] class UnknownTimeZoneError(KeyError): '''Exception raised when pytz is passed an unknown timezone. >>> isinstance(UnknownTimeZoneError(), LookupError) True This class is actually a subclass of KeyError to provide backwards compatibility with code relying on the undocumented behavior of earlier pytz releases. >>> isinstance(UnknownTimeZoneError(), KeyError) True ''' pass class InvalidTimeError(Exception): '''Base class for invalid time exceptions.''' class AmbiguousTimeError(InvalidTimeError): '''Exception raised when attempting to create an ambiguous wallclock time. At the end of a DST transition period, a particular wallclock time will occur twice (once before the clocks are set back, once after). Both possibilities may be correct, unless further information is supplied. See DstTzInfo.normalize() for more info ''' class NonExistentTimeError(InvalidTimeError): '''Exception raised when attempting to create a wallclock time that cannot exist. At the start of a DST transition period, the wallclock time jumps forward. The instants jumped over never occur. ''' pytz-2014.10/pytz/lazy.py0000644000175000017500000001221712435564046015714 0ustar jamespagejamespagefrom threading import RLock try: from UserDict import DictMixin except ImportError: from collections import Mapping as DictMixin # With lazy loading, we might end up with multiple threads triggering # it at the same time. We need a lock. _fill_lock = RLock() class LazyDict(DictMixin): """Dictionary populated on first use.""" data = None def __getitem__(self, key): if self.data is None: _fill_lock.acquire() try: if self.data is None: self._fill() finally: _fill_lock.release() return self.data[key.upper()] def __contains__(self, key): if self.data is None: _fill_lock.acquire() try: if self.data is None: self._fill() finally: _fill_lock.release() return key in self.data def __iter__(self): if self.data is None: _fill_lock.acquire() try: if self.data is None: self._fill() finally: _fill_lock.release() return iter(self.data) def __len__(self): if self.data is None: _fill_lock.acquire() try: if self.data is None: self._fill() finally: _fill_lock.release() return len(self.data) def keys(self): if self.data is None: _fill_lock.acquire() try: if self.data is None: self._fill() finally: _fill_lock.release() return self.data.keys() class LazyList(list): """List populated on first use.""" _props = [ '__str__', '__repr__', '__unicode__', '__hash__', '__sizeof__', '__cmp__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', 'append', 'count', 'index', 'extend', 'insert', 'pop', 'remove', 'reverse', 'sort', '__add__', '__radd__', '__iadd__', '__mul__', '__rmul__', '__imul__', '__contains__', '__len__', '__nonzero__', '__getitem__', '__setitem__', '__delitem__', '__iter__', '__reversed__', '__getslice__', '__setslice__', '__delslice__'] def __new__(cls, fill_iter=None): if fill_iter is None: return list() # We need a new class as we will be dynamically messing with its # methods. class LazyList(list): pass fill_iter = [fill_iter] def lazy(name): def _lazy(self, *args, **kw): _fill_lock.acquire() try: if len(fill_iter) > 0: list.extend(self, fill_iter.pop()) for method_name in cls._props: delattr(LazyList, method_name) finally: _fill_lock.release() return getattr(list, name)(self, *args, **kw) return _lazy for name in cls._props: setattr(LazyList, name, lazy(name)) new_list = LazyList() return new_list # Not all versions of Python declare the same magic methods. # Filter out properties that don't exist in this version of Python # from the list. LazyList._props = [prop for prop in LazyList._props if hasattr(list, prop)] class LazySet(set): """Set populated on first use.""" _props = ( '__str__', '__repr__', '__unicode__', '__hash__', '__sizeof__', '__cmp__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__contains__', '__len__', '__nonzero__', '__getitem__', '__setitem__', '__delitem__', '__iter__', '__sub__', '__and__', '__xor__', '__or__', '__rsub__', '__rand__', '__rxor__', '__ror__', '__isub__', '__iand__', '__ixor__', '__ior__', 'add', 'clear', 'copy', 'difference', 'difference_update', 'discard', 'intersection', 'intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update', 'union', 'update') def __new__(cls, fill_iter=None): if fill_iter is None: return set() class LazySet(set): pass fill_iter = [fill_iter] def lazy(name): def _lazy(self, *args, **kw): _fill_lock.acquire() try: if len(fill_iter) > 0: for i in fill_iter.pop(): set.add(self, i) for method_name in cls._props: delattr(LazySet, method_name) finally: _fill_lock.release() return getattr(set, name)(self, *args, **kw) return _lazy for name in cls._props: setattr(LazySet, name, lazy(name)) new_set = LazySet() return new_set # Not all versions of Python declare the same magic methods. # Filter out properties that don't exist in this version of Python # from the list. LazySet._props = [prop for prop in LazySet._props if hasattr(set, prop)] pytz-2014.10/pytz/reference.py0000664000175000017500000000710112435564046016671 0ustar jamespagejamespage''' Reference tzinfo implementations from the Python docs. Used for testing against as they are only correct for the years 1987 to 2006. Do not use these for real code. ''' from datetime import tzinfo, timedelta, datetime from pytz import utc, UTC, HOUR, ZERO # A class building tzinfo objects for fixed-offset time zones. # Note that FixedOffset(0, "UTC") is a different way to build a # UTC tzinfo object. class FixedOffset(tzinfo): """Fixed offset in minutes east from UTC.""" def __init__(self, offset, name): self.__offset = timedelta(minutes = offset) self.__name = name def utcoffset(self, dt): return self.__offset def tzname(self, dt): return self.__name def dst(self, dt): return ZERO # A class capturing the platform's idea of local time. import time as _time STDOFFSET = timedelta(seconds = -_time.timezone) if _time.daylight: DSTOFFSET = timedelta(seconds = -_time.altzone) else: DSTOFFSET = STDOFFSET DSTDIFF = DSTOFFSET - STDOFFSET class LocalTimezone(tzinfo): def utcoffset(self, dt): if self._isdst(dt): return DSTOFFSET else: return STDOFFSET def dst(self, dt): if self._isdst(dt): return DSTDIFF else: return ZERO def tzname(self, dt): return _time.tzname[self._isdst(dt)] def _isdst(self, dt): tt = (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.weekday(), 0, -1) stamp = _time.mktime(tt) tt = _time.localtime(stamp) return tt.tm_isdst > 0 Local = LocalTimezone() # A complete implementation of current DST rules for major US time zones. def first_sunday_on_or_after(dt): days_to_go = 6 - dt.weekday() if days_to_go: dt += timedelta(days_to_go) return dt # In the US, DST starts at 2am (standard time) on the first Sunday in April. DSTSTART = datetime(1, 4, 1, 2) # and ends at 2am (DST time; 1am standard time) on the last Sunday of Oct. # which is the first Sunday on or after Oct 25. DSTEND = datetime(1, 10, 25, 1) class USTimeZone(tzinfo): def __init__(self, hours, reprname, stdname, dstname): self.stdoffset = timedelta(hours=hours) self.reprname = reprname self.stdname = stdname self.dstname = dstname def __repr__(self): return self.reprname def tzname(self, dt): if self.dst(dt): return self.dstname else: return self.stdname def utcoffset(self, dt): return self.stdoffset + self.dst(dt) def dst(self, dt): if dt is None or dt.tzinfo is None: # An exception may be sensible here, in one or both cases. # It depends on how you want to treat them. The default # fromutc() implementation (called by the default astimezone() # implementation) passes a datetime with dt.tzinfo is self. return ZERO assert dt.tzinfo is self # Find first Sunday in April & the last in October. start = first_sunday_on_or_after(DSTSTART.replace(year=dt.year)) end = first_sunday_on_or_after(DSTEND.replace(year=dt.year)) # Can't compare naive to aware objects, so strip the timezone from # dt first. if start <= dt.replace(tzinfo=None) < end: return HOUR else: return ZERO Eastern = USTimeZone(-5, "Eastern", "EST", "EDT") Central = USTimeZone(-6, "Central", "CST", "CDT") Mountain = USTimeZone(-7, "Mountain", "MST", "MDT") Pacific = USTimeZone(-8, "Pacific", "PST", "PDT") pytz-2014.10/pytz/tzinfo.py0000664000175000017500000004565012435564046016257 0ustar jamespagejamespage'''Base classes and helpers for building zone specific tzinfo classes''' from datetime import datetime, timedelta, tzinfo from bisect import bisect_right try: set except NameError: from sets import Set as set import pytz from pytz.exceptions import AmbiguousTimeError, NonExistentTimeError __all__ = [] _timedelta_cache = {} def memorized_timedelta(seconds): '''Create only one instance of each distinct timedelta''' try: return _timedelta_cache[seconds] except KeyError: delta = timedelta(seconds=seconds) _timedelta_cache[seconds] = delta return delta _epoch = datetime.utcfromtimestamp(0) _datetime_cache = {0: _epoch} def memorized_datetime(seconds): '''Create only one instance of each distinct datetime''' try: return _datetime_cache[seconds] except KeyError: # NB. We can't just do datetime.utcfromtimestamp(seconds) as this # fails with negative values under Windows (Bug #90096) dt = _epoch + timedelta(seconds=seconds) _datetime_cache[seconds] = dt return dt _ttinfo_cache = {} def memorized_ttinfo(*args): '''Create only one instance of each distinct tuple''' try: return _ttinfo_cache[args] except KeyError: ttinfo = ( memorized_timedelta(args[0]), memorized_timedelta(args[1]), args[2] ) _ttinfo_cache[args] = ttinfo return ttinfo _notime = memorized_timedelta(0) def _to_seconds(td): '''Convert a timedelta to seconds''' return td.seconds + td.days * 24 * 60 * 60 class BaseTzInfo(tzinfo): # Overridden in subclass _utcoffset = None _tzname = None zone = None def __str__(self): return self.zone class StaticTzInfo(BaseTzInfo): '''A timezone that has a constant offset from UTC These timezones are rare, as most locations have changed their offset at some point in their history ''' def fromutc(self, dt): '''See datetime.tzinfo.fromutc''' if dt.tzinfo is not None and dt.tzinfo is not self: raise ValueError('fromutc: dt.tzinfo is not self') return (dt + self._utcoffset).replace(tzinfo=self) def utcoffset(self, dt, is_dst=None): '''See datetime.tzinfo.utcoffset is_dst is ignored for StaticTzInfo, and exists only to retain compatibility with DstTzInfo. ''' return self._utcoffset def dst(self, dt, is_dst=None): '''See datetime.tzinfo.dst is_dst is ignored for StaticTzInfo, and exists only to retain compatibility with DstTzInfo. ''' return _notime def tzname(self, dt, is_dst=None): '''See datetime.tzinfo.tzname is_dst is ignored for StaticTzInfo, and exists only to retain compatibility with DstTzInfo. ''' return self._tzname def localize(self, dt, is_dst=False): '''Convert naive time to local time''' if dt.tzinfo is not None: raise ValueError('Not naive datetime (tzinfo is already set)') return dt.replace(tzinfo=self) def normalize(self, dt, is_dst=False): '''Correct the timezone information on the given datetime. This is normally a no-op, as StaticTzInfo timezones never have ambiguous cases to correct: >>> from pytz import timezone >>> gmt = timezone('GMT') >>> isinstance(gmt, StaticTzInfo) True >>> dt = datetime(2011, 5, 8, 1, 2, 3, tzinfo=gmt) >>> gmt.normalize(dt) is dt True The supported method of converting between timezones is to use datetime.astimezone(). Currently normalize() also works: >>> la = timezone('America/Los_Angeles') >>> dt = la.localize(datetime(2011, 5, 7, 1, 2, 3)) >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)' >>> gmt.normalize(dt).strftime(fmt) '2011-05-07 08:02:03 GMT (+0000)' ''' if dt.tzinfo is self: return dt if dt.tzinfo is None: raise ValueError('Naive time - no tzinfo set') return dt.astimezone(self) def __repr__(self): return '' % (self.zone,) def __reduce__(self): # Special pickle to zone remains a singleton and to cope with # database changes. return pytz._p, (self.zone,) class DstTzInfo(BaseTzInfo): '''A timezone that has a variable offset from UTC The offset might change if daylight saving time comes into effect, or at a point in history when the region decides to change their timezone definition. ''' # Overridden in subclass _utc_transition_times = None # Sorted list of DST transition times in UTC _transition_info = None # [(utcoffset, dstoffset, tzname)] corresponding # to _utc_transition_times entries zone = None # Set in __init__ _tzinfos = None _dst = None # DST offset def __init__(self, _inf=None, _tzinfos=None): if _inf: self._tzinfos = _tzinfos self._utcoffset, self._dst, self._tzname = _inf else: _tzinfos = {} self._tzinfos = _tzinfos self._utcoffset, self._dst, self._tzname = self._transition_info[0] _tzinfos[self._transition_info[0]] = self for inf in self._transition_info[1:]: if inf not in _tzinfos: _tzinfos[inf] = self.__class__(inf, _tzinfos) def fromutc(self, dt): '''See datetime.tzinfo.fromutc''' if (dt.tzinfo is not None and getattr(dt.tzinfo, '_tzinfos', None) is not self._tzinfos): raise ValueError('fromutc: dt.tzinfo is not self') dt = dt.replace(tzinfo=None) idx = max(0, bisect_right(self._utc_transition_times, dt) - 1) inf = self._transition_info[idx] return (dt + inf[0]).replace(tzinfo=self._tzinfos[inf]) def normalize(self, dt): '''Correct the timezone information on the given datetime If date arithmetic crosses DST boundaries, the tzinfo is not magically adjusted. This method normalizes the tzinfo to the correct one. To test, first we need to do some setup >>> from pytz import timezone >>> utc = timezone('UTC') >>> eastern = timezone('US/Eastern') >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)' We next create a datetime right on an end-of-DST transition point, the instant when the wallclocks are wound back one hour. >>> 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)' Now, if we subtract a few minutes from it, note that the timezone information has not changed. >>> before = loc_dt - timedelta(minutes=10) >>> before.strftime(fmt) '2002-10-27 00:50:00 EST (-0500)' But we can fix that by calling the normalize method >>> before = eastern.normalize(before) >>> before.strftime(fmt) '2002-10-27 01:50:00 EDT (-0400)' The supported method of converting between timezones is to use datetime.astimezone(). Currently, normalize() also works: >>> th = timezone('Asia/Bangkok') >>> am = timezone('Europe/Amsterdam') >>> dt = th.localize(datetime(2011, 5, 7, 1, 2, 3)) >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)' >>> am.normalize(dt).strftime(fmt) '2011-05-06 20:02:03 CEST (+0200)' ''' if dt.tzinfo is None: raise ValueError('Naive time - no tzinfo set') # Convert dt in localtime to UTC offset = dt.tzinfo._utcoffset dt = dt.replace(tzinfo=None) dt = dt - offset # convert it back, and return it return self.fromutc(dt) def localize(self, dt, is_dst=False): '''Convert naive time to local time. This method should be used to construct localtimes, rather than passing a tzinfo argument to a datetime constructor. is_dst is used to determine the correct timezone in the ambigous period at the end of daylight saving time. >>> from pytz import timezone >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)' >>> amdam = timezone('Europe/Amsterdam') >>> dt = datetime(2004, 10, 31, 2, 0, 0) >>> loc_dt1 = amdam.localize(dt, is_dst=True) >>> loc_dt2 = amdam.localize(dt, is_dst=False) >>> loc_dt1.strftime(fmt) '2004-10-31 02:00:00 CEST (+0200)' >>> loc_dt2.strftime(fmt) '2004-10-31 02:00:00 CET (+0100)' >>> str(loc_dt2 - loc_dt1) '1:00:00' Use is_dst=None to raise an AmbiguousTimeError for ambiguous times at the end of daylight saving time >>> try: ... loc_dt1 = amdam.localize(dt, is_dst=None) ... except AmbiguousTimeError: ... print('Ambiguous') Ambiguous is_dst defaults to False >>> amdam.localize(dt) == amdam.localize(dt, False) True is_dst is also used to determine the correct timezone in the wallclock times jumped over at the start of daylight saving time. >>> pacific = timezone('US/Pacific') >>> dt = datetime(2008, 3, 9, 2, 0, 0) >>> ploc_dt1 = pacific.localize(dt, is_dst=True) >>> ploc_dt2 = pacific.localize(dt, is_dst=False) >>> ploc_dt1.strftime(fmt) '2008-03-09 02:00:00 PDT (-0700)' >>> ploc_dt2.strftime(fmt) '2008-03-09 02:00:00 PST (-0800)' >>> str(ploc_dt2 - ploc_dt1) '1:00:00' Use is_dst=None to raise a NonExistentTimeError for these skipped times. >>> try: ... loc_dt1 = pacific.localize(dt, is_dst=None) ... except NonExistentTimeError: ... print('Non-existent') Non-existent ''' if dt.tzinfo is not None: raise ValueError('Not naive datetime (tzinfo is already set)') # Find the two best possibilities. possible_loc_dt = set() for delta in [timedelta(days=-1), timedelta(days=1)]: loc_dt = dt + delta idx = max(0, bisect_right( self._utc_transition_times, loc_dt) - 1) inf = self._transition_info[idx] tzinfo = self._tzinfos[inf] loc_dt = tzinfo.normalize(dt.replace(tzinfo=tzinfo)) if loc_dt.replace(tzinfo=None) == dt: possible_loc_dt.add(loc_dt) if len(possible_loc_dt) == 1: return possible_loc_dt.pop() # If there are no possibly correct timezones, we are attempting # to convert a time that never happened - the time period jumped # during the start-of-DST transition period. if len(possible_loc_dt) == 0: # If we refuse to guess, raise an exception. if is_dst is None: raise NonExistentTimeError(dt) # If we are forcing the pre-DST side of the DST transition, we # obtain the correct timezone by winding the clock forward a few # hours. elif is_dst: return self.localize( dt + timedelta(hours=6), is_dst=True) - timedelta(hours=6) # If we are forcing the post-DST side of the DST transition, we # obtain the correct timezone by winding the clock back. else: return self.localize( dt - timedelta(hours=6), is_dst=False) + timedelta(hours=6) # If we get this far, we have multiple possible timezones - this # is an ambiguous case occuring during the end-of-DST transition. # If told to be strict, raise an exception since we have an # ambiguous case if is_dst is None: raise AmbiguousTimeError(dt) # Filter out the possiblilities that don't match the requested # is_dst filtered_possible_loc_dt = [ p for p in possible_loc_dt if bool(p.tzinfo._dst) == is_dst ] # Hopefully we only have one possibility left. Return it. if len(filtered_possible_loc_dt) == 1: return filtered_possible_loc_dt[0] if len(filtered_possible_loc_dt) == 0: filtered_possible_loc_dt = list(possible_loc_dt) # If we get this far, we have in a wierd timezone transition # where the clocks have been wound back but is_dst is the same # in both (eg. Europe/Warsaw 1915 when they switched to CET). # At this point, we just have to guess unless we allow more # 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 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: 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 The is_dst parameter may be used to remove ambiguity during DST transitions. >>> from pytz import timezone >>> tz = timezone('America/St_Johns') >>> ambiguous = datetime(2009, 10, 31, 23, 30) >>> tz.utcoffset(ambiguous, is_dst=False) datetime.timedelta(-1, 73800) >>> tz.utcoffset(ambiguous, is_dst=True) datetime.timedelta(-1, 77400) >>> try: ... tz.utcoffset(ambiguous) ... except AmbiguousTimeError: ... print('Ambiguous') Ambiguous ''' if dt is None: return None elif dt.tzinfo is not self: dt = self.localize(dt, is_dst) return dt.tzinfo._utcoffset else: return self._utcoffset def dst(self, dt, is_dst=None): '''See datetime.tzinfo.dst The is_dst parameter may be used to remove ambiguity during DST transitions. >>> from pytz import timezone >>> tz = timezone('America/St_Johns') >>> normal = datetime(2009, 9, 1) >>> tz.dst(normal) datetime.timedelta(0, 3600) >>> tz.dst(normal, is_dst=False) datetime.timedelta(0, 3600) >>> tz.dst(normal, is_dst=True) datetime.timedelta(0, 3600) >>> ambiguous = datetime(2009, 10, 31, 23, 30) >>> tz.dst(ambiguous, is_dst=False) datetime.timedelta(0) >>> tz.dst(ambiguous, is_dst=True) datetime.timedelta(0, 3600) >>> try: ... tz.dst(ambiguous) ... except AmbiguousTimeError: ... print('Ambiguous') Ambiguous ''' if dt is None: return None elif dt.tzinfo is not self: dt = self.localize(dt, is_dst) return dt.tzinfo._dst else: return self._dst def tzname(self, dt, is_dst=None): '''See datetime.tzinfo.tzname The is_dst parameter may be used to remove ambiguity during DST transitions. >>> from pytz import timezone >>> tz = timezone('America/St_Johns') >>> normal = datetime(2009, 9, 1) >>> tz.tzname(normal) 'NDT' >>> tz.tzname(normal, is_dst=False) 'NDT' >>> tz.tzname(normal, is_dst=True) 'NDT' >>> ambiguous = datetime(2009, 10, 31, 23, 30) >>> tz.tzname(ambiguous, is_dst=False) 'NST' >>> tz.tzname(ambiguous, is_dst=True) 'NDT' >>> try: ... tz.tzname(ambiguous) ... except AmbiguousTimeError: ... print('Ambiguous') Ambiguous ''' if dt is None: return self.zone elif dt.tzinfo is not self: dt = self.localize(dt, is_dst) return dt.tzinfo._tzname else: return self._tzname def __repr__(self): if self._dst: dst = 'DST' else: dst = 'STD' if self._utcoffset > _notime: return '' % ( self.zone, self._tzname, self._utcoffset, dst ) else: return '' % ( self.zone, self._tzname, self._utcoffset, dst ) def __reduce__(self): # Special pickle to zone remains a singleton and to cope with # database changes. return pytz._p, ( self.zone, _to_seconds(self._utcoffset), _to_seconds(self._dst), self._tzname ) def unpickler(zone, utcoffset=None, dstoffset=None, tzname=None): """Factory function for unpickling pytz tzinfo instances. This is shared for both StaticTzInfo and DstTzInfo instances, because database changes could cause a zones implementation to switch between these two base classes and we can't break pickles on a pytz version upgrade. """ # Raises a KeyError if zone no longer exists, which should never happen # and would be a bug. tz = pytz.timezone(zone) # A StaticTzInfo - just return it if utcoffset is None: return tz # This pickle was created from a DstTzInfo. We need to # determine which of the list of tzinfo instances for this zone # to use in order to restore the state of any datetime instances using # it correctly. utcoffset = memorized_timedelta(utcoffset) dstoffset = memorized_timedelta(dstoffset) try: return tz._tzinfos[(utcoffset, dstoffset, tzname)] except KeyError: # The particular state requested in this timezone no longer exists. # This indicates a corrupt pickle, or the timezone database has been # corrected violently enough to make this particular # (utcoffset,dstoffset) no longer exist in the zone, or the # abbreviation has been changed. pass # See if we can find an entry differing only by tzname. Abbreviations # get changed from the initial guess by the database maintainers to # match reality when this information is discovered. for localized_tz in tz._tzinfos.values(): if (localized_tz._utcoffset == utcoffset and localized_tz._dst == dstoffset): return localized_tz # This (utcoffset, dstoffset) information has been removed from the # zone. Add it back. This might occur when the database maintainers have # corrected incorrect information. datetime instances using this # incorrect information will continue to do so, exactly as they were # before being pickled. This is purely an overly paranoid safety net - I # doubt this will ever been needed in real life. inf = (utcoffset, dstoffset, tzname) tz._tzinfos[inf] = tz.__class__(inf, tz._tzinfos) return tz._tzinfos[inf] pytz-2014.10/pytz.egg-info/0000775000175000017500000000000012435564151016051 5ustar jamespagejamespagepytz-2014.10/pytz.egg-info/top_level.txt0000664000175000017500000000000512435564150020575 0ustar jamespagejamespagepytz pytz-2014.10/pytz.egg-info/SOURCES.txt0000664000175000017500000004217212435564151017743 0ustar jamespagejamespageCHANGES.txt LICENSE.txt MANIFEST.in README.txt setup.py pytz/__init__.py pytz/exceptions.py pytz/lazy.py pytz/reference.py pytz/tzfile.py pytz/tzinfo.py pytz.egg-info/PKG-INFO pytz.egg-info/SOURCES.txt pytz.egg-info/dependency_links.txt pytz.egg-info/top_level.txt pytz.egg-info/zip-safe pytz/tests/test_docs.py pytz/tests/test_lazy.py pytz/tests/test_tzinfo.py pytz/zoneinfo/CET pytz/zoneinfo/CST6CDT pytz/zoneinfo/Cuba pytz/zoneinfo/EET pytz/zoneinfo/EST pytz/zoneinfo/EST5EDT pytz/zoneinfo/Egypt pytz/zoneinfo/Eire pytz/zoneinfo/Factory pytz/zoneinfo/GB pytz/zoneinfo/GB-Eire pytz/zoneinfo/GMT pytz/zoneinfo/GMT+0 pytz/zoneinfo/GMT-0 pytz/zoneinfo/GMT0 pytz/zoneinfo/Greenwich pytz/zoneinfo/HST pytz/zoneinfo/Hongkong pytz/zoneinfo/Iceland pytz/zoneinfo/Iran pytz/zoneinfo/Israel pytz/zoneinfo/Jamaica pytz/zoneinfo/Japan pytz/zoneinfo/Kwajalein pytz/zoneinfo/Libya pytz/zoneinfo/MET pytz/zoneinfo/MST pytz/zoneinfo/MST7MDT pytz/zoneinfo/NZ pytz/zoneinfo/NZ-CHAT pytz/zoneinfo/Navajo pytz/zoneinfo/PRC pytz/zoneinfo/PST8PDT pytz/zoneinfo/Poland pytz/zoneinfo/Portugal pytz/zoneinfo/ROC pytz/zoneinfo/ROK pytz/zoneinfo/Singapore pytz/zoneinfo/Turkey pytz/zoneinfo/UCT pytz/zoneinfo/UTC pytz/zoneinfo/Universal pytz/zoneinfo/W-SU pytz/zoneinfo/WET pytz/zoneinfo/Zulu pytz/zoneinfo/iso3166.tab pytz/zoneinfo/localtime pytz/zoneinfo/posixrules pytz/zoneinfo/zone.tab pytz/zoneinfo/zone1970.tab pytz/zoneinfo/Africa/Abidjan pytz/zoneinfo/Africa/Accra pytz/zoneinfo/Africa/Addis_Ababa pytz/zoneinfo/Africa/Algiers pytz/zoneinfo/Africa/Asmara pytz/zoneinfo/Africa/Asmera pytz/zoneinfo/Africa/Bamako pytz/zoneinfo/Africa/Bangui pytz/zoneinfo/Africa/Banjul pytz/zoneinfo/Africa/Bissau pytz/zoneinfo/Africa/Blantyre pytz/zoneinfo/Africa/Brazzaville pytz/zoneinfo/Africa/Bujumbura pytz/zoneinfo/Africa/Cairo pytz/zoneinfo/Africa/Casablanca pytz/zoneinfo/Africa/Ceuta pytz/zoneinfo/Africa/Conakry pytz/zoneinfo/Africa/Dakar pytz/zoneinfo/Africa/Dar_es_Salaam pytz/zoneinfo/Africa/Djibouti pytz/zoneinfo/Africa/Douala pytz/zoneinfo/Africa/El_Aaiun pytz/zoneinfo/Africa/Freetown pytz/zoneinfo/Africa/Gaborone pytz/zoneinfo/Africa/Harare pytz/zoneinfo/Africa/Johannesburg pytz/zoneinfo/Africa/Juba pytz/zoneinfo/Africa/Kampala pytz/zoneinfo/Africa/Khartoum pytz/zoneinfo/Africa/Kigali pytz/zoneinfo/Africa/Kinshasa pytz/zoneinfo/Africa/Lagos pytz/zoneinfo/Africa/Libreville pytz/zoneinfo/Africa/Lome pytz/zoneinfo/Africa/Luanda pytz/zoneinfo/Africa/Lubumbashi pytz/zoneinfo/Africa/Lusaka pytz/zoneinfo/Africa/Malabo pytz/zoneinfo/Africa/Maputo pytz/zoneinfo/Africa/Maseru pytz/zoneinfo/Africa/Mbabane pytz/zoneinfo/Africa/Mogadishu pytz/zoneinfo/Africa/Monrovia pytz/zoneinfo/Africa/Nairobi pytz/zoneinfo/Africa/Ndjamena pytz/zoneinfo/Africa/Niamey pytz/zoneinfo/Africa/Nouakchott pytz/zoneinfo/Africa/Ouagadougou pytz/zoneinfo/Africa/Porto-Novo pytz/zoneinfo/Africa/Sao_Tome pytz/zoneinfo/Africa/Timbuktu pytz/zoneinfo/Africa/Tripoli pytz/zoneinfo/Africa/Tunis pytz/zoneinfo/Africa/Windhoek pytz/zoneinfo/America/Adak pytz/zoneinfo/America/Anchorage pytz/zoneinfo/America/Anguilla pytz/zoneinfo/America/Antigua pytz/zoneinfo/America/Araguaina pytz/zoneinfo/America/Aruba pytz/zoneinfo/America/Asuncion pytz/zoneinfo/America/Atikokan pytz/zoneinfo/America/Atka pytz/zoneinfo/America/Bahia pytz/zoneinfo/America/Bahia_Banderas pytz/zoneinfo/America/Barbados pytz/zoneinfo/America/Belem pytz/zoneinfo/America/Belize pytz/zoneinfo/America/Blanc-Sablon pytz/zoneinfo/America/Boa_Vista pytz/zoneinfo/America/Bogota pytz/zoneinfo/America/Boise pytz/zoneinfo/America/Buenos_Aires pytz/zoneinfo/America/Cambridge_Bay pytz/zoneinfo/America/Campo_Grande pytz/zoneinfo/America/Cancun pytz/zoneinfo/America/Caracas pytz/zoneinfo/America/Catamarca pytz/zoneinfo/America/Cayenne pytz/zoneinfo/America/Cayman pytz/zoneinfo/America/Chicago pytz/zoneinfo/America/Chihuahua pytz/zoneinfo/America/Coral_Harbour pytz/zoneinfo/America/Cordoba pytz/zoneinfo/America/Costa_Rica pytz/zoneinfo/America/Creston pytz/zoneinfo/America/Cuiaba pytz/zoneinfo/America/Curacao pytz/zoneinfo/America/Danmarkshavn pytz/zoneinfo/America/Dawson pytz/zoneinfo/America/Dawson_Creek pytz/zoneinfo/America/Denver pytz/zoneinfo/America/Detroit pytz/zoneinfo/America/Dominica pytz/zoneinfo/America/Edmonton pytz/zoneinfo/America/Eirunepe pytz/zoneinfo/America/El_Salvador pytz/zoneinfo/America/Ensenada pytz/zoneinfo/America/Fort_Wayne pytz/zoneinfo/America/Fortaleza pytz/zoneinfo/America/Glace_Bay pytz/zoneinfo/America/Godthab pytz/zoneinfo/America/Goose_Bay pytz/zoneinfo/America/Grand_Turk pytz/zoneinfo/America/Grenada pytz/zoneinfo/America/Guadeloupe pytz/zoneinfo/America/Guatemala pytz/zoneinfo/America/Guayaquil pytz/zoneinfo/America/Guyana pytz/zoneinfo/America/Halifax pytz/zoneinfo/America/Havana pytz/zoneinfo/America/Hermosillo pytz/zoneinfo/America/Indianapolis pytz/zoneinfo/America/Inuvik pytz/zoneinfo/America/Iqaluit pytz/zoneinfo/America/Jamaica pytz/zoneinfo/America/Jujuy pytz/zoneinfo/America/Juneau pytz/zoneinfo/America/Knox_IN pytz/zoneinfo/America/Kralendijk pytz/zoneinfo/America/La_Paz pytz/zoneinfo/America/Lima pytz/zoneinfo/America/Los_Angeles pytz/zoneinfo/America/Louisville pytz/zoneinfo/America/Lower_Princes pytz/zoneinfo/America/Maceio pytz/zoneinfo/America/Managua pytz/zoneinfo/America/Manaus pytz/zoneinfo/America/Marigot pytz/zoneinfo/America/Martinique pytz/zoneinfo/America/Matamoros pytz/zoneinfo/America/Mazatlan pytz/zoneinfo/America/Mendoza pytz/zoneinfo/America/Menominee pytz/zoneinfo/America/Merida pytz/zoneinfo/America/Metlakatla pytz/zoneinfo/America/Mexico_City pytz/zoneinfo/America/Miquelon pytz/zoneinfo/America/Moncton pytz/zoneinfo/America/Monterrey pytz/zoneinfo/America/Montevideo pytz/zoneinfo/America/Montreal pytz/zoneinfo/America/Montserrat pytz/zoneinfo/America/Nassau pytz/zoneinfo/America/New_York pytz/zoneinfo/America/Nipigon pytz/zoneinfo/America/Nome pytz/zoneinfo/America/Noronha pytz/zoneinfo/America/Ojinaga pytz/zoneinfo/America/Panama pytz/zoneinfo/America/Pangnirtung pytz/zoneinfo/America/Paramaribo pytz/zoneinfo/America/Phoenix pytz/zoneinfo/America/Port-au-Prince pytz/zoneinfo/America/Port_of_Spain pytz/zoneinfo/America/Porto_Acre pytz/zoneinfo/America/Porto_Velho pytz/zoneinfo/America/Puerto_Rico pytz/zoneinfo/America/Rainy_River pytz/zoneinfo/America/Rankin_Inlet pytz/zoneinfo/America/Recife pytz/zoneinfo/America/Regina pytz/zoneinfo/America/Resolute pytz/zoneinfo/America/Rio_Branco pytz/zoneinfo/America/Rosario pytz/zoneinfo/America/Santa_Isabel pytz/zoneinfo/America/Santarem pytz/zoneinfo/America/Santiago pytz/zoneinfo/America/Santo_Domingo pytz/zoneinfo/America/Sao_Paulo pytz/zoneinfo/America/Scoresbysund pytz/zoneinfo/America/Shiprock pytz/zoneinfo/America/Sitka pytz/zoneinfo/America/St_Barthelemy pytz/zoneinfo/America/St_Johns pytz/zoneinfo/America/St_Kitts pytz/zoneinfo/America/St_Lucia pytz/zoneinfo/America/St_Thomas pytz/zoneinfo/America/St_Vincent pytz/zoneinfo/America/Swift_Current pytz/zoneinfo/America/Tegucigalpa pytz/zoneinfo/America/Thule pytz/zoneinfo/America/Thunder_Bay pytz/zoneinfo/America/Tijuana pytz/zoneinfo/America/Toronto pytz/zoneinfo/America/Tortola pytz/zoneinfo/America/Vancouver pytz/zoneinfo/America/Virgin pytz/zoneinfo/America/Whitehorse pytz/zoneinfo/America/Winnipeg pytz/zoneinfo/America/Yakutat pytz/zoneinfo/America/Yellowknife pytz/zoneinfo/America/Argentina/Buenos_Aires pytz/zoneinfo/America/Argentina/Catamarca pytz/zoneinfo/America/Argentina/ComodRivadavia pytz/zoneinfo/America/Argentina/Cordoba pytz/zoneinfo/America/Argentina/Jujuy pytz/zoneinfo/America/Argentina/La_Rioja pytz/zoneinfo/America/Argentina/Mendoza pytz/zoneinfo/America/Argentina/Rio_Gallegos pytz/zoneinfo/America/Argentina/Salta pytz/zoneinfo/America/Argentina/San_Juan pytz/zoneinfo/America/Argentina/San_Luis pytz/zoneinfo/America/Argentina/Tucuman pytz/zoneinfo/America/Argentina/Ushuaia pytz/zoneinfo/America/Indiana/Indianapolis pytz/zoneinfo/America/Indiana/Knox pytz/zoneinfo/America/Indiana/Marengo pytz/zoneinfo/America/Indiana/Petersburg pytz/zoneinfo/America/Indiana/Tell_City pytz/zoneinfo/America/Indiana/Vevay pytz/zoneinfo/America/Indiana/Vincennes pytz/zoneinfo/America/Indiana/Winamac pytz/zoneinfo/America/Kentucky/Louisville pytz/zoneinfo/America/Kentucky/Monticello pytz/zoneinfo/America/North_Dakota/Beulah pytz/zoneinfo/America/North_Dakota/Center pytz/zoneinfo/America/North_Dakota/New_Salem pytz/zoneinfo/Antarctica/Casey pytz/zoneinfo/Antarctica/Davis pytz/zoneinfo/Antarctica/DumontDUrville pytz/zoneinfo/Antarctica/Macquarie pytz/zoneinfo/Antarctica/Mawson pytz/zoneinfo/Antarctica/McMurdo pytz/zoneinfo/Antarctica/Palmer pytz/zoneinfo/Antarctica/Rothera pytz/zoneinfo/Antarctica/South_Pole pytz/zoneinfo/Antarctica/Syowa pytz/zoneinfo/Antarctica/Troll pytz/zoneinfo/Antarctica/Vostok pytz/zoneinfo/Arctic/Longyearbyen pytz/zoneinfo/Asia/Aden pytz/zoneinfo/Asia/Almaty pytz/zoneinfo/Asia/Amman pytz/zoneinfo/Asia/Anadyr pytz/zoneinfo/Asia/Aqtau pytz/zoneinfo/Asia/Aqtobe pytz/zoneinfo/Asia/Ashgabat pytz/zoneinfo/Asia/Ashkhabad pytz/zoneinfo/Asia/Baghdad pytz/zoneinfo/Asia/Bahrain pytz/zoneinfo/Asia/Baku pytz/zoneinfo/Asia/Bangkok pytz/zoneinfo/Asia/Beirut pytz/zoneinfo/Asia/Bishkek pytz/zoneinfo/Asia/Brunei pytz/zoneinfo/Asia/Calcutta pytz/zoneinfo/Asia/Chita pytz/zoneinfo/Asia/Choibalsan pytz/zoneinfo/Asia/Chongqing pytz/zoneinfo/Asia/Chungking pytz/zoneinfo/Asia/Colombo pytz/zoneinfo/Asia/Dacca pytz/zoneinfo/Asia/Damascus pytz/zoneinfo/Asia/Dhaka pytz/zoneinfo/Asia/Dili pytz/zoneinfo/Asia/Dubai pytz/zoneinfo/Asia/Dushanbe pytz/zoneinfo/Asia/Gaza pytz/zoneinfo/Asia/Harbin pytz/zoneinfo/Asia/Hebron pytz/zoneinfo/Asia/Ho_Chi_Minh pytz/zoneinfo/Asia/Hong_Kong pytz/zoneinfo/Asia/Hovd pytz/zoneinfo/Asia/Irkutsk pytz/zoneinfo/Asia/Istanbul pytz/zoneinfo/Asia/Jakarta pytz/zoneinfo/Asia/Jayapura pytz/zoneinfo/Asia/Jerusalem pytz/zoneinfo/Asia/Kabul pytz/zoneinfo/Asia/Kamchatka pytz/zoneinfo/Asia/Karachi pytz/zoneinfo/Asia/Kashgar pytz/zoneinfo/Asia/Kathmandu pytz/zoneinfo/Asia/Katmandu pytz/zoneinfo/Asia/Khandyga pytz/zoneinfo/Asia/Kolkata pytz/zoneinfo/Asia/Krasnoyarsk pytz/zoneinfo/Asia/Kuala_Lumpur pytz/zoneinfo/Asia/Kuching pytz/zoneinfo/Asia/Kuwait pytz/zoneinfo/Asia/Macao pytz/zoneinfo/Asia/Macau pytz/zoneinfo/Asia/Magadan pytz/zoneinfo/Asia/Makassar pytz/zoneinfo/Asia/Manila pytz/zoneinfo/Asia/Muscat pytz/zoneinfo/Asia/Nicosia pytz/zoneinfo/Asia/Novokuznetsk pytz/zoneinfo/Asia/Novosibirsk pytz/zoneinfo/Asia/Omsk pytz/zoneinfo/Asia/Oral pytz/zoneinfo/Asia/Phnom_Penh pytz/zoneinfo/Asia/Pontianak pytz/zoneinfo/Asia/Pyongyang pytz/zoneinfo/Asia/Qatar pytz/zoneinfo/Asia/Qyzylorda pytz/zoneinfo/Asia/Rangoon pytz/zoneinfo/Asia/Riyadh pytz/zoneinfo/Asia/Saigon pytz/zoneinfo/Asia/Sakhalin pytz/zoneinfo/Asia/Samarkand pytz/zoneinfo/Asia/Seoul pytz/zoneinfo/Asia/Shanghai pytz/zoneinfo/Asia/Singapore pytz/zoneinfo/Asia/Srednekolymsk pytz/zoneinfo/Asia/Taipei pytz/zoneinfo/Asia/Tashkent pytz/zoneinfo/Asia/Tbilisi pytz/zoneinfo/Asia/Tehran pytz/zoneinfo/Asia/Tel_Aviv pytz/zoneinfo/Asia/Thimbu pytz/zoneinfo/Asia/Thimphu pytz/zoneinfo/Asia/Tokyo pytz/zoneinfo/Asia/Ujung_Pandang pytz/zoneinfo/Asia/Ulaanbaatar pytz/zoneinfo/Asia/Ulan_Bator pytz/zoneinfo/Asia/Urumqi pytz/zoneinfo/Asia/Ust-Nera pytz/zoneinfo/Asia/Vientiane pytz/zoneinfo/Asia/Vladivostok pytz/zoneinfo/Asia/Yakutsk pytz/zoneinfo/Asia/Yekaterinburg pytz/zoneinfo/Asia/Yerevan pytz/zoneinfo/Atlantic/Azores pytz/zoneinfo/Atlantic/Bermuda pytz/zoneinfo/Atlantic/Canary pytz/zoneinfo/Atlantic/Cape_Verde pytz/zoneinfo/Atlantic/Faeroe pytz/zoneinfo/Atlantic/Faroe pytz/zoneinfo/Atlantic/Jan_Mayen pytz/zoneinfo/Atlantic/Madeira pytz/zoneinfo/Atlantic/Reykjavik pytz/zoneinfo/Atlantic/South_Georgia pytz/zoneinfo/Atlantic/St_Helena pytz/zoneinfo/Atlantic/Stanley pytz/zoneinfo/Australia/ACT pytz/zoneinfo/Australia/Adelaide pytz/zoneinfo/Australia/Brisbane pytz/zoneinfo/Australia/Broken_Hill pytz/zoneinfo/Australia/Canberra pytz/zoneinfo/Australia/Currie pytz/zoneinfo/Australia/Darwin pytz/zoneinfo/Australia/Eucla pytz/zoneinfo/Australia/Hobart pytz/zoneinfo/Australia/LHI pytz/zoneinfo/Australia/Lindeman pytz/zoneinfo/Australia/Lord_Howe pytz/zoneinfo/Australia/Melbourne pytz/zoneinfo/Australia/NSW pytz/zoneinfo/Australia/North pytz/zoneinfo/Australia/Perth pytz/zoneinfo/Australia/Queensland pytz/zoneinfo/Australia/South pytz/zoneinfo/Australia/Sydney pytz/zoneinfo/Australia/Tasmania pytz/zoneinfo/Australia/Victoria pytz/zoneinfo/Australia/West pytz/zoneinfo/Australia/Yancowinna pytz/zoneinfo/Brazil/Acre pytz/zoneinfo/Brazil/DeNoronha pytz/zoneinfo/Brazil/East pytz/zoneinfo/Brazil/West pytz/zoneinfo/Canada/Atlantic pytz/zoneinfo/Canada/Central pytz/zoneinfo/Canada/East-Saskatchewan pytz/zoneinfo/Canada/Eastern pytz/zoneinfo/Canada/Mountain pytz/zoneinfo/Canada/Newfoundland pytz/zoneinfo/Canada/Pacific pytz/zoneinfo/Canada/Saskatchewan pytz/zoneinfo/Canada/Yukon pytz/zoneinfo/Chile/Continental pytz/zoneinfo/Chile/EasterIsland pytz/zoneinfo/Etc/GMT pytz/zoneinfo/Etc/GMT+0 pytz/zoneinfo/Etc/GMT+1 pytz/zoneinfo/Etc/GMT+10 pytz/zoneinfo/Etc/GMT+11 pytz/zoneinfo/Etc/GMT+12 pytz/zoneinfo/Etc/GMT+2 pytz/zoneinfo/Etc/GMT+3 pytz/zoneinfo/Etc/GMT+4 pytz/zoneinfo/Etc/GMT+5 pytz/zoneinfo/Etc/GMT+6 pytz/zoneinfo/Etc/GMT+7 pytz/zoneinfo/Etc/GMT+8 pytz/zoneinfo/Etc/GMT+9 pytz/zoneinfo/Etc/GMT-0 pytz/zoneinfo/Etc/GMT-1 pytz/zoneinfo/Etc/GMT-10 pytz/zoneinfo/Etc/GMT-11 pytz/zoneinfo/Etc/GMT-12 pytz/zoneinfo/Etc/GMT-13 pytz/zoneinfo/Etc/GMT-14 pytz/zoneinfo/Etc/GMT-2 pytz/zoneinfo/Etc/GMT-3 pytz/zoneinfo/Etc/GMT-4 pytz/zoneinfo/Etc/GMT-5 pytz/zoneinfo/Etc/GMT-6 pytz/zoneinfo/Etc/GMT-7 pytz/zoneinfo/Etc/GMT-8 pytz/zoneinfo/Etc/GMT-9 pytz/zoneinfo/Etc/GMT0 pytz/zoneinfo/Etc/Greenwich pytz/zoneinfo/Etc/UCT pytz/zoneinfo/Etc/UTC pytz/zoneinfo/Etc/Universal pytz/zoneinfo/Etc/Zulu pytz/zoneinfo/Europe/Amsterdam pytz/zoneinfo/Europe/Andorra pytz/zoneinfo/Europe/Athens pytz/zoneinfo/Europe/Belfast pytz/zoneinfo/Europe/Belgrade pytz/zoneinfo/Europe/Berlin pytz/zoneinfo/Europe/Bratislava pytz/zoneinfo/Europe/Brussels pytz/zoneinfo/Europe/Bucharest pytz/zoneinfo/Europe/Budapest pytz/zoneinfo/Europe/Busingen pytz/zoneinfo/Europe/Chisinau pytz/zoneinfo/Europe/Copenhagen pytz/zoneinfo/Europe/Dublin pytz/zoneinfo/Europe/Gibraltar pytz/zoneinfo/Europe/Guernsey pytz/zoneinfo/Europe/Helsinki pytz/zoneinfo/Europe/Isle_of_Man pytz/zoneinfo/Europe/Istanbul pytz/zoneinfo/Europe/Jersey pytz/zoneinfo/Europe/Kaliningrad pytz/zoneinfo/Europe/Kiev pytz/zoneinfo/Europe/Lisbon pytz/zoneinfo/Europe/Ljubljana pytz/zoneinfo/Europe/London pytz/zoneinfo/Europe/Luxembourg pytz/zoneinfo/Europe/Madrid pytz/zoneinfo/Europe/Malta pytz/zoneinfo/Europe/Mariehamn pytz/zoneinfo/Europe/Minsk pytz/zoneinfo/Europe/Monaco pytz/zoneinfo/Europe/Moscow pytz/zoneinfo/Europe/Nicosia pytz/zoneinfo/Europe/Oslo pytz/zoneinfo/Europe/Paris pytz/zoneinfo/Europe/Podgorica pytz/zoneinfo/Europe/Prague pytz/zoneinfo/Europe/Riga pytz/zoneinfo/Europe/Rome pytz/zoneinfo/Europe/Samara pytz/zoneinfo/Europe/San_Marino pytz/zoneinfo/Europe/Sarajevo pytz/zoneinfo/Europe/Simferopol pytz/zoneinfo/Europe/Skopje pytz/zoneinfo/Europe/Sofia pytz/zoneinfo/Europe/Stockholm pytz/zoneinfo/Europe/Tallinn pytz/zoneinfo/Europe/Tirane pytz/zoneinfo/Europe/Tiraspol pytz/zoneinfo/Europe/Uzhgorod pytz/zoneinfo/Europe/Vaduz pytz/zoneinfo/Europe/Vatican pytz/zoneinfo/Europe/Vienna pytz/zoneinfo/Europe/Vilnius pytz/zoneinfo/Europe/Volgograd pytz/zoneinfo/Europe/Warsaw pytz/zoneinfo/Europe/Zagreb pytz/zoneinfo/Europe/Zaporozhye pytz/zoneinfo/Europe/Zurich pytz/zoneinfo/Indian/Antananarivo pytz/zoneinfo/Indian/Chagos pytz/zoneinfo/Indian/Christmas pytz/zoneinfo/Indian/Cocos pytz/zoneinfo/Indian/Comoro pytz/zoneinfo/Indian/Kerguelen pytz/zoneinfo/Indian/Mahe pytz/zoneinfo/Indian/Maldives pytz/zoneinfo/Indian/Mauritius pytz/zoneinfo/Indian/Mayotte pytz/zoneinfo/Indian/Reunion pytz/zoneinfo/Mexico/BajaNorte pytz/zoneinfo/Mexico/BajaSur pytz/zoneinfo/Mexico/General pytz/zoneinfo/Pacific/Apia pytz/zoneinfo/Pacific/Auckland pytz/zoneinfo/Pacific/Bougainville pytz/zoneinfo/Pacific/Chatham pytz/zoneinfo/Pacific/Chuuk pytz/zoneinfo/Pacific/Easter pytz/zoneinfo/Pacific/Efate pytz/zoneinfo/Pacific/Enderbury pytz/zoneinfo/Pacific/Fakaofo pytz/zoneinfo/Pacific/Fiji pytz/zoneinfo/Pacific/Funafuti pytz/zoneinfo/Pacific/Galapagos pytz/zoneinfo/Pacific/Gambier pytz/zoneinfo/Pacific/Guadalcanal pytz/zoneinfo/Pacific/Guam pytz/zoneinfo/Pacific/Honolulu pytz/zoneinfo/Pacific/Johnston pytz/zoneinfo/Pacific/Kiritimati pytz/zoneinfo/Pacific/Kosrae pytz/zoneinfo/Pacific/Kwajalein pytz/zoneinfo/Pacific/Majuro pytz/zoneinfo/Pacific/Marquesas pytz/zoneinfo/Pacific/Midway pytz/zoneinfo/Pacific/Nauru pytz/zoneinfo/Pacific/Niue pytz/zoneinfo/Pacific/Norfolk pytz/zoneinfo/Pacific/Noumea pytz/zoneinfo/Pacific/Pago_Pago pytz/zoneinfo/Pacific/Palau pytz/zoneinfo/Pacific/Pitcairn pytz/zoneinfo/Pacific/Pohnpei pytz/zoneinfo/Pacific/Ponape pytz/zoneinfo/Pacific/Port_Moresby pytz/zoneinfo/Pacific/Rarotonga pytz/zoneinfo/Pacific/Saipan pytz/zoneinfo/Pacific/Samoa pytz/zoneinfo/Pacific/Tahiti pytz/zoneinfo/Pacific/Tarawa pytz/zoneinfo/Pacific/Tongatapu pytz/zoneinfo/Pacific/Truk pytz/zoneinfo/Pacific/Wake pytz/zoneinfo/Pacific/Wallis pytz/zoneinfo/Pacific/Yap pytz/zoneinfo/US/Alaska pytz/zoneinfo/US/Aleutian pytz/zoneinfo/US/Arizona pytz/zoneinfo/US/Central pytz/zoneinfo/US/East-Indiana pytz/zoneinfo/US/Eastern pytz/zoneinfo/US/Hawaii pytz/zoneinfo/US/Indiana-Starke pytz/zoneinfo/US/Michigan pytz/zoneinfo/US/Mountain pytz/zoneinfo/US/Pacific pytz/zoneinfo/US/Pacific-New pytz/zoneinfo/US/Samoapytz-2014.10/pytz.egg-info/zip-safe0000664000175000017500000000000112435564047017505 0ustar jamespagejamespage pytz-2014.10/pytz.egg-info/PKG-INFO0000664000175000017500000005752112435564150017157 0ustar jamespagejamespageMetadata-Version: 1.1 Name: pytz Version: 2014.10 Summary: World timezone definitions, modern and historical Home-page: http://pythonhosted.org/pytz Author: Stuart Bishop Author-email: stuart@stuartbishop.net License: MIT Download-URL: http://pypi.python.org/pypi/pytz Description: 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 Keywords: timezone,tzinfo,datetime,olson,time Platform: Independant Classifier: Development Status :: 6 - Mature Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Software Development :: Libraries :: Python Modules pytz-2014.10/pytz.egg-info/dependency_links.txt0000664000175000017500000000000112435564150022116 0ustar jamespagejamespage pytz-2014.10/MANIFEST.in0000664000175000017500000000017412435564046015114 0ustar jamespagejamespageinclude *.txt setup.py recursive-include pytz *.py #recursive-include pytz *.pot graft pytz/zoneinfo #exclude test_zdump.py pytz-2014.10/setup.cfg0000664000175000017500000000007312435564151015172 0ustar jamespagejamespage[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 pytz-2014.10/README.txt0000664000175000017500000004516312435564046015063 0ustar jamespagejamespagepytz - 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 pytz-2014.10/PKG-INFO0000664000175000017500000005752112435564151014460 0ustar jamespagejamespageMetadata-Version: 1.1 Name: pytz Version: 2014.10 Summary: World timezone definitions, modern and historical Home-page: http://pythonhosted.org/pytz Author: Stuart Bishop Author-email: stuart@stuartbishop.net License: MIT Download-URL: http://pypi.python.org/pypi/pytz Description: 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 Keywords: timezone,tzinfo,datetime,olson,time Platform: Independant Classifier: Development Status :: 6 - Mature Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Software Development :: Libraries :: Python Modules pytz-2014.10/setup.py0000664000175000017500000000310112435564046015061 0ustar jamespagejamespage''' pytz setup script ''' import pytz, sys, os, os.path try: from setuptools import setup except ImportError: from distutils.core import setup me = 'Stuart Bishop' memail = 'stuart@stuartbishop.net' packages = ['pytz'] resources = ['zone.tab', 'locales/pytz.pot'] for dirpath, dirnames, filenames in os.walk(os.path.join('pytz', 'zoneinfo')): # remove the 'pytz' part of the path basepath = dirpath.split(os.path.sep, 1)[1] resources.extend([os.path.join(basepath, filename) for filename in filenames]) package_data = {'pytz': resources} assert len(resources) > 10, 'zoneinfo files not found!' setup ( name='pytz', version=pytz.VERSION, zip_safe=True, description='World timezone definitions, modern and historical', long_description=open('README.txt','r').read(), author=me, author_email=memail, maintainer=me, maintainer_email=memail, url='http://pythonhosted.org/pytz', license='MIT', keywords=['timezone','tzinfo', 'datetime', 'olson', 'time'], packages=packages, package_data=package_data, download_url='http://pypi.python.org/pypi/pytz', platforms=['Independant'], classifiers = [ 'Development Status :: 6 - Mature', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Natural Language :: English', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 3', 'Topic :: Software Development :: Libraries :: Python Modules', ], ) pytz-2014.10/CHANGES.txt0000664000175000017500000000275612435564046015177 0ustar jamespagejamespage2004-07-25 - Improved localtime handling, and added a localize() method enabling correct creation of local times. 2005-02-16 - Made available under the Zope Public Licence 2.1 (ZPL) and checked into the Zope3 project. pytz may now be used and redistributed under either the original MIT license or the ZPL 2.1. 2005-05-13 - Move UTC into the top level pytz module and provide special case pickle support for this singleton. 2005-08-14 - Ensure all tzinfo instances are efficiently picklable. 2005-12-31 - Add fixed offset timezone classes required by Zope 3 - Generate and distribute a PO template file listing all timezone names. Translations are not yet available. 2007-03-03 - Import work by James Henstridge, making pytz load timezone information from zic compiled binaries at runtime rather than processing them into Python classes. 2007-03-26 - Update database to version 2007d - Fix windows incompatibilities, working around limitations on that platform. - Fix 2.3 incompatibilities. Installation now requires distutils. - Passing an invalid timezone name to timezone() now raises an UnknownTimezoneError, which is a KeyError subclass for backwards compatibility. 2007-03-27 - Ensure API can accept Unicode strings (Bug #96957) 2009-09-29 - Fix test_zdump tests and bugs the fixed tests picked up, including the fix for Bug #427444. 2011-02-08 - Python 3.1 support.