¿Cómo traduzco una cadena datetime ISO 8601 en un objeto datetime de Python?

Recibo una cadena de fecha y hora en un formato como “2009-05-28T16: 15: 00” (esto es ISO 8601, creo). Una opción de pirateo parece ser analizar la cadena usando time.strptime y pasar los primeros seis elementos de la tupla al constructor de fecha y hora, como:

 datetime.datetime(*time.strptime("2007-03-04T21:08:12", "%Y-%m-%dT%H:%M:%S")[:6]) 

No he podido encontrar una manera “más limpia” de hacer esto. Hay uno

Prefiero usar la biblioteca dateutil para el manejo de la zona horaria y el análisis de fecha generalmente sólido. Si obtuvieras una cadena ISO 8601 como: 2010-05-08T23: 41: 54.000Z te divertirías analizando eso con strptime, especialmente si no sabías desde el principio si la zona horaria estaba incluida o no. pyiso8601 tiene un par de problemas (verifique su rastreador) que encontré durante mi uso y no se ha actualizado en algunos años. dateutil, por el contrario, ha sido activo y ha trabajado para mí:

 import dateutil.parser yourdate = dateutil.parser.parse(datestring) 

Con Python 3 y sin bibliotecas externas:

 datetime.datetime.strptime('2019-01-04T16:41:24+0200', "%Y-%m-%dT%H:%M:%S%z") 

Python 2 no es compatible con el especificador de formato %z , por lo que es mejor utilizar explícitamente la hora Zulu en todas partes si es posible:

 datetime.datetime.strptime("2007-03-04T21:08:12Z", "%Y-%m-%dT%H:%M:%SZ") 

Debido a que ISO 8601 permite que existan muchas variaciones de dos puntos y guiones opcionales, básicamente CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm] . Si desea utilizar strptime, primero debe eliminar esas variaciones.

El objective es generar un objeto datetime UTC.


Si solo desea un caso básico que funcione para UTC con el sufijo Z como 2016-06-29T19:36:29.3453Z :

 datetime.datetime.strptime(timestamp.translate(None, ':-'), "%Y%m%dT%H%M%S.%fZ") 

Si desea manejar las compensaciones de zona horaria como 2016-06-29T19:36:29.3453-0400 o 2008-09-03T20:56:35.450686+05:00 use lo siguiente. Estos convertirán todas las variaciones en algo sin delimitadores variables como 20080903T205635.450686+0500 lo que hace que sea más consistente / más fácil de analizar.

 import re # This regex removes all colons and all # dashes EXCEPT for the dash indicating + or - utc offset for the timezone conformed_timestamp = re.sub(r"[:]|([-](?!((\d{2}[:]\d{2})|(\d{4}))$))", '', timestamp) datetime.datetime.strptime(conformed_timestamp, "%Y%m%dT%H%M%S.%f%z" ) 

Si su sistema no admite la directiva %z strptime (ve algo como ValueError: 'z' is a bad directive in format '%Y%m%dT%H%M%S.%f%z' ), entonces necesita para desplazar manualmente el tiempo desde Z (UTC). Es posible que la nota %z no funcione en su sistema en las versiones de Python <3, ya que depende del soporte de la biblioteca C que varía según el tipo de compilación del sistema / Python (es decir, Jython , Cython , etc.).

 import re import datetime # This regex removes all colons and all # dashes EXCEPT for the dash indicating + or - utc offset for the timezone conformed_timestamp = re.sub(r"[:]|([-](?!((\d{2}[:]\d{2})|(\d{4}))$))", '', timestamp) # Split on the offset to remove it. Use a capture group to keep the delimiter split_timestamp = re.split(r"[+|-]",conformed_timestamp) main_timestamp = split_timestamp[0] if len(split_timestamp) == 3: sign = split_timestamp[1] offset = split_timestamp[2] else: sign = None offset = None # Generate the datetime object without the offset at UTC time output_datetime = datetime.datetime.strptime(main_timestamp +"Z", "%Y%m%dT%H%M%S.%fZ" ) if offset: # Create timedelta based on offset offset_delta = datetime.timedelta(hours=int(sign+offset[:-2]), minutes=int(sign+offset[-2:])) # Offset datetime with timedelta output_datetime = output_datetime + offset_delta 

Arrow se ve prometedor para esto:

 >>> import arrow >>> arrow.get('2014-11-13T14:53:18.694072+00:00').datetime datetime.datetime(2014, 11, 13, 14, 53, 18, 694072, tzinfo=tzoffset(None, 0)) 

Arrow es una biblioteca de Python que proporciona una forma sensata e inteligente de crear, manipular, formatear y convertir fechas y horas. Arrow es simple, ligero y muy inspirado por moment.js y pedidos .

Debe mantener un ojo en la información de la zona horaria, ya que podría tener problemas al comparar tiempos de datos no compatibles con tz con datos compatibles con tz.

Probablemente sea lo mejor hacerlos siempre conscientes de tz (aunque solo sea como UTC), a menos que realmente sepa por qué no sería de ninguna utilidad hacerlo.

 #----------------------------------------------- import datetime import pytz import dateutil.parser #----------------------------------------------- utc = pytz.utc BERLIN = pytz.timezone('Europe/Berlin') #----------------------------------------------- def to_iso8601(when=None, tz=BERLIN): if not when: when = datetime.datetime.now(tz) if not when.tzinfo: when = tz.localize(when) _when = when.strftime("%Y-%m-%dT%H:%M:%S.%f%z") return _when[:-8] + _when[-5:] # Remove microseconds #----------------------------------------------- def from_iso8601(when=None, tz=BERLIN): _when = dateutil.parser.parse(when) if not _when.tzinfo: _when = tz.localize(_when) return _when #----------------------------------------------- 

No lo he probado todavía, pero pyiso8601 promete apoyar esto.

Ambos sentidos:

Época del tiempo ISO:

 isoTime = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime(epochTime)) 

ISO tiempo a la época:

 epochTime = time.mktime(time.strptime(isoTime, '%Y-%m-%dT%H:%M:%SZ')) 
 import datetime, time def convert_enddate_to_seconds(self, ts): """Takes ISO 8601 format(string) and converts into epoch time.""" dt = datetime.datetime.strptime(ts[:-7],'%Y-%m-%dT%H:%M:%S.%f')+\ datetime.timedelta(hours=int(ts[-5:-3]), minutes=int(ts[-2:]))*int(ts[-6:-5]+'1') seconds = time.mktime(dt.timetuple()) + dt.microsecond/1000000.0 return seconds 

Esto también incluye los milisegundos y la zona horaria.

Si el tiempo es ‘2012-09-30T15: 31: 50.262-08: 00’, esto se convertirá en tiempo de época.

 >>> import datetime, time >>> ts = '2012-09-30T15:31:50.262-08:00' >>> dt = datetime.datetime.strptime(ts[:-7],'%Y-%m-%dT%H:%M:%S.%f')+ datetime.timedelta(hours=int(ts[-5:-3]), minutes=int(ts[-2:]))*int(ts[-6:-5]+'1') >>> seconds = time.mktime(dt.timetuple()) + dt.microsecond/1000000.0 >>> seconds 1348990310.26 

Isodate parece tener el soporte más completo.

aniso8601 debe manejar esto. También entiende las zonas horarias, Python 2 y Python 3, y tiene una cobertura razonable del rest de ISO 8601 , si alguna vez lo necesita.

 import aniso8601 aniso8601.parse_datetime('2007-03-04T21:08:12') 

Aquí hay una forma súper simple de hacer este tipo de conversiones. Sin análisis, o bibliotecas adicionales requeridas. Es limpio, simple y rápido.

 import datetime import time ################################################ # # Takes the time (in seconds), # and returns a string of the time in ISO8601 format. # Note: Timezone is UTC # ################################################ def TimeToISO8601(seconds): strKv = datetime.datetime.fromtimestamp(seconds).strftime('%Y-%m-%d') strKv = strKv + "T" strKv = strKv + datetime.datetime.fromtimestamp(seconds).strftime('%H:%M:%S') strKv = strKv +"Z" return strKv ################################################ # # Takes a string of the time in ISO8601 format, # and returns the time (in seconds). # Note: Timezone is UTC # ################################################ def ISO8601ToTime(strISOTime): K1 = 0 K2 = 9999999999 K3 = 0 counter = 0 while counter < 95: K3 = (K1 + K2) / 2 strK4 = TimeToISO8601(K3) if strK4 < strISOTime: K1 = K3 if strK4 > strISOTime: K2 = K3 counter = counter + 1 return K3 ################################################ # # Takes a string of the time in ISO8601 (UTC) format, # and returns a python DateTime object. # Note: returned value is your local time zone. # ################################################ def ISO8601ToDateTime(strISOTime): return time.gmtime(ISO8601ToTime(strISOTime)) #To test: Test = "2014-09-27T12:05:06.9876" print ("The test value is: " + Test) Ans = ISO8601ToTime(Test) print ("The answer in seconds is: " + str(Ans)) print ("And a Python datetime object is: " + str(ISO8601ToDateTime(Test)))