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''
(instanciaDstTzInfo
)? - ¿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
.