from datetime import tzinfo, timedelta, datetime ZERO = timedelta(0) HOUR = timedelta(hours=1) # Una classe UTC. class UTC(tzinfo): """UTC""" def utcoffset(self, dt): return ZERO def tzname(self, dt): return "UTC" def dst(self, dt): return ZERO utc = UTC() # Una classe che crea oggetti tzinfo per fusi orari con distanza # oraria fissa dall'UTC. Notate che FixedOffset(0, "UTC") è un # altro modo per creare un oggetto tzinfo rappresentante l'UTC. class FixedOffset(tzinfo): """Distanza fissa in minuti ad est dell'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 # Una classe che cattura il concetto di tempo locale #+ supportato dalla piattaforma 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() # Una comleta implementazioni delle regole correnti di DST (ora legale) # per i principali fusi orari degli Stati Uniti. def first_sunday_on_or_after(dt): days_to_go = 6 - dt.weekday() if days_to_go: dt += timedelta(days_to_go) return dt # Negli Stati Uniti, il DST comincia alle 2 AM (tempo standard) della # prima domenica di Aprile. DSTSTART = datetime(1, 4, 1, 2) # e termina alle 2 AM (tempo DST: 1 AM tempo standard) dell'ultima # domenica di ottobre, cioè la prima domenica a partire dal 25 Ottobre, # incluso questo giorno. 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: # Un'eccezione può essere una buona idea qui, in uno od # entrambi i casi. Dipende da come li si vuole trattare. # L'implementazione di default di fromutc() ( chiamata dalla # implementazione di default di astimezone() ) passa un oggetto # datetime "dt" in cui dt.tzinfo è uguale a self. return ZERO assert dt.tzinfo is self # Trova la prima domenica di Aprile e l'ultima di Ottobre. start = first_sunday_on_or_after(DSTSTART.replace(year=dt.year)) end = first_sunday_on_or_after(DSTEND.replace(year=dt.year)) # Non è possibile confrontare oggetti consapevoli con altri # semplicistici, per cui è meglio prima rimuovere da dt # l'informazione sul fuso orario. 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")