""" open/DurusWorks/qp/lib/tz.py Adapted from http://www.python.org/doc/2.3.5/lib/tzinfo-examples.txt """ from datetime import tzinfo, timedelta, datetime from types import FunctionType import sys class ClassMethodsClass (type): """ A class that uses this class as its type gets all of its methods (except those with names that start with '__') converted into class methods. This is a way to define classes that can act as singleton instances. The str method of classes with this metaclass returns the name of the class. """ def __init__(self, class_name, bases, namespace): for name, obj in namespace.items(): if isinstance(obj, FunctionType) and not name.startswith('__'): setattr(self, name, classmethod(obj)) def __str__(self): return self.__name__ ClassMethods = ClassMethodsClass('ClassMethods', (object,), {}) class _tzinfoclass (ClassMethodsClass, tzinfo): """ Classes with this class are *instances* of tzinfo. (!) All of the non __* methods are automatically converted to classmethods. """ # Make name shadowing explicit. __getattribute__ = type.__getattribute__ __new__ = type.__new__ def now(klass): """ The current time, with this timezone. """ return datetime.now(klass) TimeZone = _tzinfoclass('TimeZone', (object,), {}) class UTCOffset (TimeZone): _utc_offset = timedelta(0) _name = "UTC?" _dst = timedelta(0) def utcoffset(klass, dt): return klass._utc_offset def tzname(klass, dt): return klass._name def dst(klass, dt): return klass._dst class UTC (UTCOffset): _name = "UTC" _ZERO_TIME = timedelta(hours=0) _HOUR = timedelta(hours=1) class _US (TimeZone): # 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) def tzname(klass, dt): if klass.dst(dt): return klass.dstname else: return klass.stdname def utcoffset(klass, dt): return klass.stdoffset + klass.dst(dt) def dst(klass, 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 klass. return _ZERO_TIME assert dt.tzinfo is klass def first_sunday_on_or_after(dt): days_to_go = 6 - dt.weekday() if days_to_go: dt += timedelta(days_to_go) return dt # Find first Sunday in April & the last in October. start = first_sunday_on_or_after(klass._DSTSTART.replace(year=dt.year)) end = first_sunday_on_or_after(klass._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_TIME class Eastern (_US): stdoffset = timedelta(hours=-5) stdname = "EST" dstname = "EDT" class Central (_US): stdoffset = timedelta(hours=-6) stdname = "CST" dstname = "CDT" class Mountain (_US): stdoffset = timedelta(hours=-7) stdname = "MST" dstname = "MDT" class Pacific (_US): stdoffset = timedelta(hours=-8) stdname = "PST" dstname = "PDT" class UTC_plus_1 (UTCOffset): _name = "UTC+1" _utc_offset = timedelta(hours=1) class UTC_minus_1 (UTCOffset): _name = "UTC-1" _utc_offset = timedelta(hours=-1) class UTC_plus_2 (UTCOffset): _name = "UTC+2" _utc_offset = timedelta(hours=2) class UTC_minus_2 (UTCOffset): _name = "UTC-2" _utc_offset = timedelta(hours=-2) class UTC_plus_3 (UTCOffset): _name = "UTC+3" _utc_offset = timedelta(hours=3) class UTC_minus_3 (UTCOffset): _name = "UTC-3" _utc_offset = timedelta(hours=-3) class UTC_plus_4 (UTCOffset): _name = "UTC+4" _utc_offset = timedelta(hours=4) class UTC_minus_4 (UTCOffset): _name = "UTC-4" _utc_offset = timedelta(hours=-4) class UTC_plus_5 (UTCOffset): _name = "UTC+5" _utc_offset = timedelta(hours=5) class UTC_minus_5 (UTCOffset): _name = "UTC-5" _utc_offset = timedelta(hours=-5) class UTC_plus_6 (UTCOffset): _name = "UTC+6" _utc_offset = timedelta(hours=6) class UTC_minus_6 (UTCOffset): _name = "UTC-6" _utc_offset = timedelta(hours=-6) class UTC_plus_7 (UTCOffset): _name = "UTC+7" _utc_offset = timedelta(hours=7) class UTC_minus_7 (UTCOffset): _name = "UTC-7" _utc_offset = timedelta(hours=-7) class UTC_plus_8 (UTCOffset): _name = "UTC+8" _utc_offset = timedelta(hours=8) class UTC_minus_8 (UTCOffset): _name = "UTC-8" _utc_offset = timedelta(hours=-8) class UTC_plus_9 (UTCOffset): _name = "UTC+9" _utc_offset = timedelta(hours=9) class UTC_minus_9 (UTCOffset): _name = "UTC-9" _utc_offset = timedelta(hours=-9) class UTC_plus_10 (UTCOffset): _name = "UTC+10" _utc_offset = timedelta(hours=10) class UTC_minus_10 (UTCOffset): _name = "UTC-10" _utc_offset = timedelta(hours=-10) class UTC_plus_11 (UTCOffset): _name = "UTC+11" _utc_offset = timedelta(hours=11) class UTC_minus_11 (UTCOffset): _name = "UTC-11" _utc_offset = timedelta(hours=-11) class UTC_plus_12 (UTCOffset): _name = "UTC+12" _utc_offset = timedelta(hours=12) class UTC_minus_12 (UTCOffset): _name = "UTC-12" _utc_offset = timedelta(hours=-12) def now(tzinfo=UTC): return datetime.now(tzinfo) def list_timezones(): return _US.__subclasses__() + UTCOffset.__subclasses__()