Permalink
Browse files

update bundled pytz

add to requirements.txt so that pip installs use that instead
add /usr/share/lib/zoneinfo to list of system tzdata dirs
  • Loading branch information...
1 parent 9899f7e commit 9beda6e2a87c70dab0b29f8e64cb0f85bb6dd4f5 @mleinart mleinart committed Feb 11, 2012
View
1 requirements.txt
@@ -36,5 +36,6 @@ txAMQP==0.4
simplejson==2.1.6
django-tagging==0.3.1
gunicorn
+pytz
http://cairographics.org/releases/py2cairo-1.8.10.tar.gz
./whisper
View
267 webapp/graphite/thirdparty/pytz/__init__.py
@@ -9,7 +9,7 @@
'''
# The Olson database is updated several times a year.
-OLSON_VERSION = '2010b'
+OLSON_VERSION = '2011n'
VERSION = OLSON_VERSION
# Version format for a patch release - only one so far.
#VERSION = OLSON_VERSION + '.2'
@@ -26,22 +26,59 @@
]
import sys, datetime, os.path, gettext
-from UserDict import DictMixin
+try:
+ from UserDict import DictMixin
+except ImportError:
+ from collections import Mapping as DictMixin
try:
from pkg_resources import resource_stream
except ImportError:
resource_stream = None
-from tzinfo import AmbiguousTimeError, InvalidTimeError, NonExistentTimeError
-from tzinfo import unpickler
-from tzfile import build_tzinfo
+from pytz.exceptions import AmbiguousTimeError
+from pytz.exceptions import InvalidTimeError
+from pytz.exceptions import NonExistentTimeError
+from pytz.exceptions import UnknownTimeZoneError
+from pytz.tzinfo import unpickler
+from pytz.tzfile import build_tzinfo, _byte_string
+
-# Use 2.3 sets module implementation if set builtin is not available
try:
- set
-except NameError:
- from sets import Set as set
+ 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):
@@ -50,19 +87,24 @@ def open_resource(name):
Uses the pkg_resources module if available and no standard file
found at the calculated location.
"""
- # Patched in Debian, use the system zoninfo from the tzdata package
+ # Patched in Debian, use the system zoneinfo from the tzdata package
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('/usr/share/zoneinfo', *name_parts)
+ for possible_path in [ '/usr/share/zoneinfo', '/usr/share/lib/zoneinfo' ]:
+ if os.path.exists(possible_path):
+ tz_path = possible_path
+ break
+
+ filename = os.path.join(tz_path, *name_parts)
return open(filename, 'rb')
def resource_exists(name):
"""Return true if the given resource exists"""
try:
- open_resource(name)
+ open_resource(name).close()
return True
except IOError:
return False
@@ -83,22 +125,6 @@ def resource_exists(name):
# return t.ugettext(timezone_name)
-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
-
-
_tzinfo_cache = {}
def timezone(zone):
@@ -109,7 +135,7 @@ def timezone(zone):
>>> eastern = timezone('US/Eastern')
>>> eastern.zone
'US/Eastern'
- >>> timezone(u'US/Eastern') is 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)
@@ -125,29 +151,36 @@ def timezone(zone):
Raises UnknownTimeZoneError if passed an unknown zone.
- >>> timezone('Asia/Shangri-La')
- Traceback (most recent call last):
- ...
- UnknownTimeZoneError: 'Asia/Shangri-La'
+ >>> try:
+ ... timezone('Asia/Shangri-La')
+ ... except UnknownTimeZoneError:
+ ... print('Unknown')
+ Unknown
+
+ >>> try:
+ ... timezone(unicode('\N{TRADE MARK SIGN}'))
+ ... except UnknownTimeZoneError:
+ ... print('Unknown')
+ Unknown
- >>> timezone(u'\N{TRADE MARK SIGN}')
- Traceback (most recent call last):
- ...
- UnknownTimeZoneError: u'\u2122'
'''
if zone.upper() == 'UTC':
return utc
try:
- zone = zone.encode('US-ASCII')
+ 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:
- _tzinfo_cache[zone] = build_tzinfo(zone, open_resource(zone))
+ fp = open_resource(zone)
+ try:
+ _tzinfo_cache[zone] = build_tzinfo(zone, fp)
+ finally:
+ fp.close()
else:
raise UnknownTimeZoneError(zone)
@@ -175,6 +208,15 @@ class UTC(datetime.tzinfo):
"""
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
@@ -190,13 +232,13 @@ def __reduce__(self):
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)'
+ 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'
+ raise ValueError('Naive time - no tzinfo set')
return dt.replace(tzinfo=self)
def __repr__(self):
@@ -224,8 +266,8 @@ def _UTC():
>>> naive = dt.replace(tzinfo=None)
>>> p = pickle.dumps(dt, 1)
>>> naive_p = pickle.dumps(naive, 1)
- >>> len(p), len(naive_p), len(p) - len(naive_p)
- (60, 43, 17)
+ >>> len(p) - len(naive_p)
+ 17
>>> new = pickle.loads(p)
>>> new == dt
True
@@ -260,6 +302,21 @@ def __getitem__(self, key):
self._fill()
return self.data[key.upper()]
+ def __contains__(self, key):
+ if self.data is None:
+ self._fill()
+ return key in self.data
+
+ def __iter__(self):
+ if self.data is None:
+ self._fill()
+ return iter(self.data)
+
+ def __len__(self):
+ if self.data is None:
+ self._fill()
+ return len(self.data)
+
def keys(self):
if self.data is None:
self._fill()
@@ -272,22 +329,31 @@ class _CountryTimezoneDict(_LazyDict):
iso3166_code is the two letter code used to identify the country.
- >>> country_timezones['ch']
- ['Europe/Zurich']
- >>> country_timezones['CH']
- ['Europe/Zurich']
- >>> country_timezones[u'ch']
- ['Europe/Zurich']
- >>> country_timezones['XXX']
+ >>> 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::
- >>> country_timezones('nz')
- ['Pacific/Auckland', 'Pacific/Chatham']
+ >>> print_list(country_timezones('nz'))
+ Pacific/Auckland
+ Pacific/Chatham
"""
def __call__(self, iso3166_code):
"""Backwards compatibility."""
@@ -296,36 +362,44 @@ def __call__(self, iso3166_code):
def _fill(self):
data = {}
zone_tab = open_resource('zone.tab')
- for line in zone_tab:
- 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
+ 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.
- >>> country_names['au']
- 'Australia'
+ >>> print(country_names['au'])
+ Australia
'''
def _fill(self):
data = {}
zone_tab = open_resource('iso3166.tab')
- for line in zone_tab.readlines():
- if line.startswith('#'):
- continue
- code, name = line.split(None, 1)
- data[code] = name.strip()
- self.data = data
+ 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()
@@ -349,7 +423,7 @@ def __reduce__(self):
return FixedOffset, (self._minutes, )
def dst(self, dt):
- return None
+ return ZERO
def tzname(self, dt):
return None
@@ -360,13 +434,13 @@ def __repr__(self):
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)'
+ 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'
+ raise ValueError('Naive time - no tzinfo set')
return dt.replace(tzinfo=self)
@@ -378,12 +452,16 @@ def FixedOffset(offset, _tzinfos = {}):
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.
@@ -471,6 +549,7 @@ def _test():
'Africa/Gaborone',
'Africa/Harare',
'Africa/Johannesburg',
+ 'Africa/Juba',
'Africa/Kampala',
'Africa/Khartoum',
'Africa/Kigali',
@@ -521,6 +600,7 @@ def _test():
'America/Atikokan',
'America/Atka',
'America/Bahia',
+ 'America/Bahia_Banderas',
'America/Barbados',
'America/Belem',
'America/Belize',
@@ -584,10 +664,12 @@ def _test():
'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',
@@ -598,6 +680,7 @@ def _test():
'America/Mendoza',
'America/Menominee',
'America/Merida',
+ 'America/Metlakatla',
'America/Mexico_City',
'America/Miquelon',
'America/Moncton',
@@ -610,6 +693,7 @@ def _test():
'America/Nipigon',
'America/Nome',
'America/Noronha',
+ 'America/North_Dakota/Beulah',
'America/North_Dakota/Center',
'America/North_Dakota/New_Salem',
'America/Ojinaga',
@@ -636,6 +720,7 @@ def _test():
'America/Sao_Paulo',
'America/Scoresbysund',
'America/Shiprock',
+ 'America/Sitka',
'America/St_Barthelemy',
'America/St_Johns',
'America/St_Kitts',
@@ -658,6 +743,7 @@ def _test():
'Antarctica/Casey',
'Antarctica/Davis',
'Antarctica/DumontDUrville',
+ 'Antarctica/Macquarie',
'Antarctica/Mawson',
'Antarctica/McMurdo',
'Antarctica/Palmer',
@@ -694,6 +780,7 @@ def _test():
'Asia/Dushanbe',
'Asia/Gaza',
'Asia/Harbin',
+ 'Asia/Hebron',
'Asia/Ho_Chi_Minh',
'Asia/Hong_Kong',
'Asia/Hovd',
@@ -946,6 +1033,7 @@ def _test():
'Pacific/Apia',
'Pacific/Auckland',
'Pacific/Chatham',
+ 'Pacific/Chuuk',
'Pacific/Easter',
'Pacific/Efate',
'Pacific/Enderbury',
@@ -971,6 +1059,7 @@ def _test():
'Pacific/Pago_Pago',
'Pacific/Palau',
'Pacific/Pitcairn',
+ 'Pacific/Pohnpei',
'Pacific/Ponape',
'Pacific/Port_Moresby',
'Pacific/Rarotonga',
@@ -1038,6 +1127,7 @@ def _test():
'Africa/Gaborone',
'Africa/Harare',
'Africa/Johannesburg',
+ 'Africa/Juba',
'Africa/Kampala',
'Africa/Khartoum',
'Africa/Kigali',
@@ -1085,6 +1175,7 @@ def _test():
'America/Asuncion',
'America/Atikokan',
'America/Bahia',
+ 'America/Bahia_Banderas',
'America/Barbados',
'America/Belem',
'America/Belize',
@@ -1139,17 +1230,21 @@ def _test():
'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',
@@ -1162,6 +1257,7 @@ def _test():
'America/Nipigon',
'America/Nome',
'America/Noronha',
+ 'America/North_Dakota/Beulah',
'America/North_Dakota/Center',
'America/North_Dakota/New_Salem',
'America/Ojinaga',
@@ -1185,6 +1281,9 @@ def _test():
'America/Santo_Domingo',
'America/Sao_Paulo',
'America/Scoresbysund',
+ 'America/Shiprock',
+ 'America/Sitka',
+ 'America/St_Barthelemy',
'America/St_Johns',
'America/St_Kitts',
'America/St_Lucia',
@@ -1205,12 +1304,15 @@ def _test():
'Antarctica/Casey',
'Antarctica/Davis',
'Antarctica/DumontDUrville',
+ 'Antarctica/Macquarie',
'Antarctica/Mawson',
'Antarctica/McMurdo',
'Antarctica/Palmer',
'Antarctica/Rothera',
+ 'Antarctica/South_Pole',
'Antarctica/Syowa',
'Antarctica/Vostok',
+ 'Arctic/Longyearbyen',
'Asia/Aden',
'Asia/Almaty',
'Asia/Amman',
@@ -1235,6 +1337,7 @@ def _test():
'Asia/Dushanbe',
'Asia/Gaza',
'Asia/Harbin',
+ 'Asia/Hebron',
'Asia/Ho_Chi_Minh',
'Asia/Hong_Kong',
'Asia/Hovd',
@@ -1320,42 +1423,54 @@ def _test():
'Europe/Athens',
'Europe/Belgrade',
'Europe/Berlin',
+ 'Europe/Bratislava',
'Europe/Brussels',
'Europe/Bucharest',
'Europe/Budapest',
'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',
@@ -1373,6 +1488,7 @@ def _test():
'Pacific/Apia',
'Pacific/Auckland',
'Pacific/Chatham',
+ 'Pacific/Chuuk',
'Pacific/Easter',
'Pacific/Efate',
'Pacific/Enderbury',
@@ -1398,14 +1514,13 @@ def _test():
'Pacific/Pago_Pago',
'Pacific/Palau',
'Pacific/Pitcairn',
- 'Pacific/Ponape',
+ 'Pacific/Pohnpei',
'Pacific/Port_Moresby',
'Pacific/Rarotonga',
'Pacific/Saipan',
'Pacific/Tahiti',
'Pacific/Tarawa',
'Pacific/Tongatapu',
- 'Pacific/Truk',
'Pacific/Wake',
'Pacific/Wallis',
'US/Alaska',
View
48 webapp/graphite/thirdparty/pytz/exceptions.py
@@ -0,0 +1,48 @@
+'''
+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.
+ '''
View
29 webapp/graphite/thirdparty/pytz/tzfile.py
@@ -3,13 +3,25 @@
$Id: tzfile.py,v 1.8 2004/06/03 00:15:24 zenzen Exp $
'''
-from cStringIO import StringIO
+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'
@@ -18,7 +30,7 @@ def build_tzinfo(zone, fp):
typecnt, charcnt) = unpack(head_fmt, fp.read(head_size))
# Make sure it is a tzfile(5) file
- assert magic == 'TZif'
+ 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(
@@ -43,10 +55,11 @@ def build_tzinfo(zone, fp):
# have we looked up this timezone name yet?
tzname_offset = ttinfo_raw[i+2]
if tzname_offset not in tznames:
- nul = tznames_raw.find('\0', tzname_offset)
+ nul = tznames_raw.find(_NULL, tzname_offset)
if nul < 0:
nul = len(tznames_raw)
- tznames[tzname_offset] = tznames_raw[tzname_offset:nul]
+ tznames[tzname_offset] = _std_string(
+ tznames_raw[tzname_offset:nul])
ttinfo.append((ttinfo_raw[i],
bool(ttinfo_raw[i+1]),
tznames[tzname_offset]))
@@ -84,7 +97,9 @@ def build_tzinfo(zone, fp):
break
dst = inf[0] - prev_inf[0] # dst offset
- if dst <= 0: # Bad dst? Look further.
+ # 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]:
@@ -98,8 +113,8 @@ def build_tzinfo(zone, fp):
# 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
+ 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(
View
246 webapp/graphite/thirdparty/pytz/tzinfo.py
@@ -8,6 +8,7 @@
from sets import Set as set
import pytz
+from pytz.exceptions import AmbiguousTimeError, NonExistentTimeError
__all__ = []
@@ -73,31 +74,68 @@ class StaticTzInfo(BaseTzInfo):
'''
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):
- '''See datetime.tzinfo.utcoffset'''
+ 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):
- '''See datetime.tzinfo.dst'''
+ 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):
- '''See datetime.tzinfo.tzname'''
+ 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)'
+ 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'''
+ '''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.replace(tzinfo=self)
+ raise ValueError('Naive time - no tzinfo set')
+ return dt.astimezone(self)
def __repr__(self):
return '<StaticTzInfo %r>' % (self.zone,)
@@ -135,11 +173,13 @@ def __init__(self, _inf=None, _tzinfos=None):
self._utcoffset, self._dst, self._tzname = self._transition_info[0]
_tzinfos[self._transition_info[0]] = self
for inf in self._transition_info[1:]:
- if not _tzinfos.has_key(inf):
+ 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 dt.tzinfo._tzinfos 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]
@@ -179,9 +219,19 @@ def normalize(self, dt):
>>> 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'
+ raise ValueError('Naive time - no tzinfo set')
# Convert dt in localtime to UTC
offset = dt.tzinfo._utcoffset
@@ -215,10 +265,11 @@ def localize(self, dt, is_dst=False):
Use is_dst=None to raise an AmbiguousTimeError for ambiguous
times at the end of daylight savings
- >>> loc_dt1 = amdam.localize(dt, is_dst=None)
- Traceback (most recent call last):
- [...]
- AmbiguousTimeError: 2004-10-31 02:00:00
+ >>> try:
+ ... loc_dt1 = amdam.localize(dt, is_dst=None)
+ ... except AmbiguousTimeError:
+ ... print('Ambiguous')
+ Ambiguous
is_dst defaults to False
@@ -242,13 +293,14 @@ def localize(self, dt, is_dst=False):
Use is_dst=None to raise a NonExistentTimeError for these skipped
times.
- >>> loc_dt1 = pacific.localize(dt, is_dst=None)
- Traceback (most recent call last):
- [...]
- NonExistentTimeError: 2008-03-09 02:00:00
+ >>> 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)'
+ raise ValueError('Not naive datetime (tzinfo is already set)')
# Find the two best possibilities.
possible_loc_dt = set()
@@ -317,25 +369,120 @@ def localize(self, dt, is_dst=False):
# but that is just getting silly.
#
# Choose the earliest (by UTC) applicable timezone.
- def mycmp(a,b):
- return cmp(
- a.replace(tzinfo=None) - a.tzinfo._utcoffset,
- b.replace(tzinfo=None) - b.tzinfo._utcoffset,
- )
- filtered_possible_loc_dt.sort(mycmp)
- return filtered_possible_loc_dt[0]
-
- def utcoffset(self, dt):
- '''See datetime.tzinfo.utcoffset'''
- return self._utcoffset
+ sorting_keys = {}
+ for local_dt in filtered_possible_loc_dt:
+ key = local_dt.replace(tzinfo=None) - local_dt.tzinfo._utcoffset
+ sorting_keys[key] = local_dt
+ first_key = sorted(sorting_keys)[0]
+ return sorting_keys[first_key]
- def dst(self, dt):
- '''See datetime.tzinfo.dst'''
- return self._dst
+ def utcoffset(self, dt, is_dst=None):
+ '''See datetime.tzinfo.utcoffset
- def tzname(self, dt):
- '''See datetime.tzinfo.tzname'''
- return self._tzname
+ 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:
@@ -362,29 +509,6 @@ def __reduce__(self):
)
-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.
- '''
-
def unpickler(zone, utcoffset=None, dstoffset=None, tzname=None):
"""Factory function for unpickling pytz tzinfo instances.

0 comments on commit 9beda6e

Please sign in to comment.