from create change biblioteca argentina python python-2.7 datetime timezone pytz

create - python timezone argentina



Conversión de zona horaria de Datetime usando pytz (1)

Esta es solo otra publicación en pytz .

Hay dos funciones para convertir objetos de fecha y hora entre dos zonas horarias. La segunda función funciona para todos los casos. La primera función falla en dos casos, (3) y (4). Publicaciones SO similares no tenían un problema como este. Cualquier explicación basada en la diferencia entre localize(datetime.datetime) y replace(tzinfo) sería de gran ayuda.

>>> from dateutil.parser import parse >>> import pytz

Primera función (buggy)

La función a continuación usa datetime.datetime.replace(tzinfo) .

def buggy_timezone_converter(input_dt, current_tz=''UTC'', target_tz=''US/Eastern''): ''''''input_dt is a datetime.datetime object'''''' current_tz = pytz.timezone(current_tz) target_tz = pytz.timezone(target_tz) target_dt = input_dt.replace(tzinfo=current_tz).astimezone(target_tz) return target_tz.normalize(target_dt)

Observe las cuatro conversiones de fecha y hora ahora.

(1) de UTC a EST - OK

>>> buggy_timezone_converter(parse(''2013-02-26T04:00:00'')) Out[608]: datetime.datetime(2013, 2, 25, 23, 0, tzinfo=<DstTzInfo ''US/Eastern'' EST-1 day, 19:00:00 STD>)

(2) de UTC a EDT - OK

>>> buggy_timezone_converter(parse(''2013-05-26T04:00:00'')) Out[609]: datetime.datetime(2013, 5, 26, 0, 0, tzinfo=<DstTzInfo ''US/Eastern'' EDT-1 day, 20:00:00 DST>)

(3) de EST a UTC - No está bien. El tiempo de compensación es de 4 horas y 56 minutos. Se supone que es de 5 horas

>>> buggy_timezone_converter(parse(''2013-02-26T04:00:00''), target_tz=''UTC'', current_tz=''US/Eastern'') Out[610]: datetime.datetime(2013, 2, 26, 8, 56, tzinfo=<UTC>)

(4) de EDT a UTC - No está bien. El tiempo de compensación es de 4 horas y 56 minutos. Se supone que es de 4 horas. No se considera el horario de verano.

>>> buggy_timezone_converter(parse(''2013-05-26T04:00:00''), current_tz=''US/Eastern'', target_tz=''UTC'') Out[611]: datetime.datetime(2013, 5, 26, 8, 56, tzinfo=<UTC>)

Segunda función (Funciona perfectamente)

La función siguiente utiliza pytz.timezone.localize(datetime.datetime) . Funciona a la perfección

def good_timezone_converter(input_dt, current_tz=''UTC'', target_tz=''US/Eastern''): current_tz = pytz.timezone(current_tz) target_tz = pytz.timezone(target_tz) target_dt = current_tz.localize(input_dt).astimezone(target_tz) return target_tz.normalize(target_dt)

(1) de UTC a EST - OK

>>> good_timezone_converter(parse(''2013-02-26T04:00:00'')) Out[618]: datetime.datetime(2013, 2, 25, 23, 0, tzinfo=<DstTzInfo ''US/Eastern'' EST-1 day, 19:00:00 STD>)

(2) de UTC a EDT - OK

>>> good_timezone_converter(parse(''2013-05-26T04:00:00'')) Out[619]: datetime.datetime(2013, 5, 26, 0, 0, tzinfo=<DstTzInfo ''US/Eastern'' EDT-1 day, 20:00:00 DST>)

(3) de EST a UTC - OK.

>>> good_timezone_converter(parse(''2013-02-26T04:00:00''), current_tz=''US/Eastern'', target_tz=''UTC'') Out[621]: datetime.datetime(2013, 2, 26, 9, 0, tzinfo=<UTC>)

(4) de EDT a UTC - OK.

>>> good_timezone_converter(parse(''2013-05-26T04:00:00''), current_tz=''US/Eastern'', target_tz=''UTC'') Out[620]: datetime.datetime(2013, 5, 26, 8, 0, tzinfo=<UTC>)


Supongo que tienes estas preguntas:

  • ¿Por qué funciona la primera función para la zona horaria UTC?
  • ¿Por qué falla para ''US/Eastern'' zona horaria ''US/Eastern'' (instancia DstTzInfo )?
  • ¿Por qué funciona la segunda función para todos los ejemplos proporcionados?

La primera función es incorrecta porque usa d.replace(tzinfo=dsttzinfo_instance) lugar de dsttzinfo_instance.localize(d) .

La segunda función es correcta la mayor parte del tiempo, excepto durante tiempos ambiguos o inexistentes, por ejemplo, durante las transiciones DST: puede cambiar el comportamiento pasando el parámetro .localize() a .localize() : False (predeterminado) / True / None (subir un excepción).

La primera función funciona para la zona horaria UTC porque tiene un desplazamiento utc fijo (cero) para cualquier fecha. Otros husos horarios como America/New_York pueden tener diferentes desplazamientos utc en diferentes momentos (Horario de verano, tiempo de guerra, cada vez que algún político local pueda pensar que es una buena idea, puede ser cualquier cosa , la base de datos tz funciona en la mayoría de los casos ) Para implementar tzinfo.utcoffset(dt) , tzinfo.tzname(dt) , tzinfo.dst(dt) methods pytz usa una colección de instancias DstTzInfo cada una con un conjunto diferente de (_tzname, _utcoffset, _dst) . Dado el método dt (fecha / hora) e is_dst , .localize() elige una instancia DstTzInfo apropiada (en la mayoría de los casos, pero no siempre ) de la colección. pytz.timezone(''America/New_York'') devuelve una instancia DstTzInfo con (_tzname, _utcoffset, _dst) que corresponden a un momento indocumentado en el tiempo (diferentes versiones de pytz pueden devolver valores diferentes; la versión actual puede devolver la instancia tzinfo que corresponde a la fecha más temprana para la que está disponible zoneinfo: no desea este valor la mayor parte del tiempo: creo que la motivación detrás de la elección del valor predeterminado es resaltar el error (pasando el constructor pytz.timezone a datetime o .replace() método).

Para resumir: .localize() selecciona utcoffset apropiado, tzname, dst values, .replace() usa el valor predeterminado (inadecuado). UTC tiene solo un conjunto de utcoffset, tzname, dst, por lo tanto, se puede usar el valor predeterminado y el método .replace() funciona con la zona horaria UTC. is_dst pasar un objeto datetime y el parámetro is_dst para seleccionar los valores apropiados para otras zonas horarias como ''America/New_York'' .

En principio, pytz podría haber llamado al método localize() para implementar los utcoffset() , tzname() , dst() incluso si dt.tzinfo == self : haría estos métodos O (log n) en el tiempo donde n es el número de intervalos con diferentes valores (utcoffset, tzname, dst) pero datetime constructor y .replace() funcionarían como lo es, es decir, la llamada localize() explícita sería necesaria solo para pasar is_dst .