2012-04-24 8 views
10

He estado luchando durante demasiado tiempo en fechas/zonas horarias en Python y estaba pensando que alguien podría echarme una mano aquí.Python pase tzinfo a fecha inocente sin pytz

Básicamente quiero hacer una conversión en UTC y teniendo en cuenta los cambios de horario de verano.

que he creado la siguiente tzinfo clase de uno de los tutoriales de Python (no 100% exacto sé, pero no tiene por qué):

from datetime import tzinfo, timedelta, datetime 

ZERO = timedelta(0) 
HOUR = timedelta(hours=1) 

def first_sunday_on_or_after(dt): 
    days_to_go = 6 - dt.weekday() 
    if days_to_go: 
     dt += timedelta(days_to_go) 
    return dt 

DSTSTART_2007 = datetime(1, 3, 8, 2) 
DSTEND_2007 = datetime(1, 11, 1, 1) 
DSTSTART_1987_2006 = datetime(1, 4, 1, 2) 
DSTEND_1987_2006 = datetime(1, 10, 25, 1) 
DSTSTART_1967_1986 = datetime(1, 4, 24, 2) 
DSTEND_1967_1986 = DSTEND_1987_2006 

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 start and end times for US DST. For years before 1967, return 
     # ZERO for no DST. 
     if 2006 < dt.year: 
      dststart, dstend = DSTSTART_2007, DSTEND_2007 
     elif 1986 < dt.year < 2007: 
      dststart, dstend = DSTSTART_1987_2006, DSTEND_1987_2006 
     elif 1966 < dt.year < 1987: 
      dststart, dstend = DSTSTART_1967_1986, DSTEND_1967_1986 
     else: 
      return ZERO 

     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 

Por otro lado tengo una arbitraria date objeto en EST, y quiero saber el número de horas que difieren tomando en cuenta el horario de verano.

he intentado algo como esto:

>>> Eastern = ustimezone.USTimeZone(-5, "Eastern", "EST", "EDT") 
>>> x = datetime.date.today() # I actually get an arbitrary date but this is for the example 
>>> x_dt = datetime.datetime.combine(x, datetime.time()) 
>>> x_dt_tz = x_dt.astimezone(Eastern) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: astimezone() cannot be applied to a naive datetime 

He visto varios mensajes que le dicen a utilizar localize del módulo pytz, pero por desgracia no soy capaz de utilizar módulos adicionales, tan imposible de usar pyzt

¿Alguien sabe cómo puedo conseguir este datetime ingenuo en un objeto timezoned sin usar pytz?

+1

x_dt.replace (tzinfo = Este) tal vez? De leer: http://groups.google.com/group/google-appengine/browse_thread/thread/17add9b3070aad7e/b995fe7e1f16cd4e –

+1

@skyl perfect, x_dt.replace (tzinfo = Eastern) .utcoffset() devuelve datetime.timedelta (-1 , 72000) que corresponde a -4 horas! Eso parece complicado para algo tan simple, pero gracias por la ayuda, debes publicarlo como respuesta y lo aceptaré. –

+0

manejar el horario de verano sin 'pytz' es como manejar varios idiomas sin Unicode. Se puede hacer, pero el resultado será incorrecto en la cantidad de casos. – jfs

Respuesta

7

Utilice x_dt.replace(tzinfo=Eastern) (found from this Google Groups thread).

x_dt.replace(tzinfo=Eastern).utcoffset() devuelve datetime.timedelta(-1, 72000) que corresponde a -4 horas! (del comentario de la pregunta)

11

Por lo que vale, la respuesta @skyl proporcionada es más o menos equivalente a lo que pytz hace.

Aquí está la fuente relevante pytz. Simplemente llama replace en el objeto datetime con el tzinfo kwarg:

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) 
+2

+1 para encontrar la fuente –

+0

@CharlesMenguy: no, no es lo que 'pytz' hace para las zonas horarias con horario de verano (*" Quiero hacer una conversión en UTC y teniendo en cuenta los cambios de horario de verano. "*). Puede usar '.replace()' solo con las zonas horarias de desplazamiento fijo como UTC (el mismo desplazamiento UTC desde el comienzo hasta el final). – jfs

Cuestiones relacionadas