¿Cómo preservar la zona horaria al analizar cadenas de fecha/hora con strptime()?
Tengo un archivo de volcado CSV de una copia de seguridad de IPD de Blackberry, creado con IPDDump. Las cadenas de fecha/hora aquí se ven más o menos así (donde EST
hay una zona horaria australiana):
Tue Jun 22 07:46:22 EST 2010
Necesito poder analizar esta fecha en Python. Al principio, intenté utilizar la strptime()
función de datettime.
>>> datetime.datetime.strptime('Tue Jun 22 12:10:20 2010 EST', '%a %b %d %H:%M:%S %Y %Z')
Sin embargo, por alguna razón, el datetime
objeto que regresa no parece tener ningún tzinfo
asociado.
Leí en esta página que aparentemente datetime.strptime
se descarta en silencio tzinfo
, sin embargo, revisé la documentación y no puedo encontrar nada documentado en ese sentido aquí .
¿ Hay alguna manera de strptime()
jugar bien con las zonas horarias?
Recomiendo usar python-dateutil . Su analizador ha podido analizar todos los formatos de fecha que le he aplicado hasta ahora.
>>> from dateutil import parser
>>> parser.parse("Tue Jun 22 07:46:22 EST 2010")
datetime.datetime(2010, 6, 22, 7, 46, 22, tzinfo=tzlocal())
>>> parser.parse("Fri, 11 Nov 2011 03:18:09 -0400")
datetime.datetime(2011, 11, 11, 3, 18, 9, tzinfo=tzoffset(None, -14400))
>>> parser.parse("Sun")
datetime.datetime(2011, 12, 18, 0, 0)
>>> parser.parse("10-11-08")
datetime.datetime(2008, 10, 11, 0, 0)
etcétera. No hay que lidiar con strptime()
tonterías de formato... simplemente ponle una fecha y hará lo correcto.
Dado que strptime
devuelve un objeto de fecha y hora que tiene tzinfo
un atributo, simplemente podemos reemplazarlo con la zona horaria deseada.
>>> import datetime
>>> date_time_str = '2018-06-29 08:15:27.243860'
>>> date_time_obj = datetime.datetime.strptime(date_time_str, '%Y-%m-%d %H:%M:%S.%f').replace(tzinfo=datetime.timezone.utc)
>>> date_time_obj.tzname()
'UTC'
La datetime
documentación del módulo dice:
Devuelve una fecha y hora correspondiente a date_string, analizada según el formato. Esto equivale a
datetime(*(time.strptime(date_string, format)[0:6]))
.
Mira eso [0:6]
? Eso te atrapa (year, month, day, hour, minute, second)
. Nada más. No se mencionan zonas horarias.
Curiosamente, [Win XP SP2, Python 2.6, 2.7] pasar su ejemplo time.strptime
no funciona, pero si elimina "%Z" y "EST" sí funciona. También funciona el uso de "UTC" o "GMT" en lugar de "EST". "PST" y "MEZ" no funcionan. Misterioso.
Vale la pena señalar que esto se actualizó a partir de la versión 3.2 y la misma documentación ahora también indica lo siguiente:
Cuando se proporciona la directiva %z al método strptime(), se generará un objeto de fecha y hora consciente. El tzinfo del resultado se establecerá en una instancia de zona horaria.
Tenga en cuenta que esto no funciona con %Z, por lo que el caso es importante. Vea el siguiente ejemplo:
In [1]: from datetime import datetime
In [2]: start_time = datetime.strptime('2018-04-18-17-04-30-AEST','%Y-%m-%d-%H-%M-%S-%Z')
In [3]: print("TZ NAME: {tz}".format(tz=start_time.tzname()))
TZ NAME: None
In [4]: start_time = datetime.strptime('2018-04-18-17-04-30-+1000','%Y-%m-%d-%H-%M-%S-%z')
In [5]: print("TZ NAME: {tz}".format(tz=start_time.tzname()))
TZ NAME: UTC+10:00
Su cadena de tiempo es similar al formato de hora en rfc 2822 (formato de fecha en correo electrónico, encabezados http) . Podrías analizarlo usando solo stdlib:
>>> from email.utils import parsedate_tz
>>> parsedate_tz('Tue Jun 22 07:46:22 EST 2010')
(2010, 6, 22, 7, 46, 22, 0, 1, -1, -18000)
Vea soluciones que generan objetos de fecha y hora que reconocen la zona horaria para varias versiones de Python: análisis de la fecha con la zona horaria de un correo electrónico .
En este formato, EST
es semánticamente equivalente a-0500
. Aunque, en general, una abreviatura de zona horaria no es suficiente para identificar una zona horaria de forma única .