Conversi贸n de cadenas a fecha y hora en Python

    Introducci贸n

    Uno de los muchos problemas comunes que enfrentamos en el desarrollo de software es el manejo de fechas y horas. Despu茅s de obtener una cadena de fecha y hora de una API, por ejemplo, necesitamos convertirla a un formato legible por humanos. Nuevamente, si se usa la misma API en diferentes zonas horarias, la conversi贸n ser谩 diferente. Una buena biblioteca de fecha y hora deber铆a convertir la hora seg煤n la zona horaria. Este es solo uno de los muchos matices que deben manejarse cuando se trata de fechas y horas.

    Afortunadamente, Python viene con el m贸dulo incorporado datetime para tratar con fechas y horas. Como probablemente adivin贸, viene con varias funciones para manipular fechas y horas. Con este m贸dulo, podemos analizar f谩cilmente cualquier cadena de fecha y hora y convertirla en una datetime objeto.

    Conversi贸n de cadenas con datetime

    los fecha y hora El m贸dulo consta de tres tipos de objetos diferentes: date, timey datetime. Obviamente el date el objeto contiene la fecha, time retiene el tiempo, y datetime contiene la fecha y la hora.

    Por ejemplo, el siguiente c贸digo imprimir谩 la fecha y hora actuales:

    import datetime
    
    print ('Current date/time: {}'.format(datetime.datetime.now()))
    

    Ejecutar este c贸digo imprimir谩 algo similar a esto:

    $ python3 datetime-print-1.py
    Current date/time: 2018-06-29 08:15:27.243860
    

    Cuando no se proporciona un formato personalizado, se utiliza el formato de cadena predeterminado, es decir, el formato para “2018-06-29 08: 15: 27.243860” est谩 en ISO 8601 formato (AAAA-MM-DDTHH: MM: SS.mmmmmm). Si nuestra cadena de entrada para crear un datetime El objeto tiene el mismo formato ISO 8601, podemos analizarlo f谩cilmente en un datetime objeto.

    Echemos un vistazo al siguiente c贸digo:

    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')
    
    print('Date:', date_time_obj.date())
    print('Time:', date_time_obj.time())
    print('Date-time:', date_time_obj)
    

    Ejecutarlo imprimir谩 la fecha, hora y fecha-hora:

    $ python3 datetime-print-2.py
    Date: 2018-06-29
    Time: 08:15:27.243860
    Date-time: 2018-06-29 08:15:27.243860
    

    En este ejemplo, estamos usando un nuevo m茅todo llamado strptime. Este m茅todo toma dos argumentos: el primero es la representaci贸n de cadena de la fecha y hora y el segundo es el formato de la cadena de entrada. Especificar el formato de esta manera hace que el an谩lisis sea mucho m谩s r谩pido, ya que datetime no necesita intentar interpretar el formato por s铆 solo, que es mucho m谩s costoso computacionalmente. El valor de retorno es del tipo datetime.

    En nuestro ejemplo, "2018-06-29 08:15:27.243860" es la cadena de entrada y "%Y-%m-%d %H:%M:%S.%f" es el formato de nuestra cadena de fecha. El retorno datetime el valor se almacena en date_time_obj variable. Dado que este es un datetime objeto, podemos llamar al date() y time() m茅todos directamente en 茅l. Como puede ver en la salida, imprime la parte ‘fecha’ y ‘hora’ de la cadena de entrada.

    Quiz谩s se pregunte cu谩l es el significado del formato "%Y-%m-%d %H:%M:%S.%f". Estos se conocen como tokens de formato. Cada token representa una parte diferente de la fecha y hora, como d铆a, mes, a帽o, etc. documentaci贸n strptime para ver la lista de todos los diferentes tipos de c贸digo de formato admitidos en Python. Para una referencia r谩pida, esto es lo que estamos usando en el c贸digo anterior:

    • %Y: A帽o (4 d铆gitos)
    • %m: Mes
    • %d: Dia del mes
    • %H: Hora (24 horas)
    • %M: Minutos
    • %S: Segundos
    • %f: Microsegundos

    Se espera que todos estos tokens, excepto el a帽o, tengan un relleno de ceros.

    Entonces, si se conoce el formato de una cadena, se puede analizar f谩cilmente a un datetime objeto usando strptime. D茅jame mostrarte un ejemplo m谩s no trivial:

    import datetime
    
    date_time_str="Jun 28 2018 7:40AM"
    date_time_obj = datetime.datetime.strptime(date_time_str, '%b %d %Y %I:%M%p')
    
    print('Date:', date_time_obj.date())
    print('Time:', date_time_obj.time())
    print('Date-time:', date_time_obj)
    

    En el siguiente resultado, puede ver que la cadena se analiz贸 correctamente, ya que el datetime objeto aqu铆:

    $ python3 datetime-print-3.py
    Date: 2018-06-28
    Time: 07:40:00
    Date-time: 2018-06-28 07:40:00
    

    A continuaci贸n, se muestran algunos ejemplos m谩s de formatos de tiempo de uso com煤n y los tokens utilizados para el an谩lisis:

    "Jun 28 2018 at 7:40AM" -> "%b %d %Y at %I:%M%p"
    "September 18, 2017, 22:19:55" -> "%B %d, %Y, %H:%M:%S"
    "Sun,05/12/99,12:30PM" -> "%a,%d/%m/%y,%I:%M%p"
    "Mon, 21 March, 2015" -> "%a, %d %B, %Y"
    "2018-03-12T10:12:45Z" -> "%Y-%m-%dT%H:%M:%SZ"
    

    Puede analizar una cadena de fecha y hora de cualquier formato utilizando la tabla mencionada en la documentaci贸n strptime.

    Tratar con las zonas horarias y la fecha y hora

    El manejo de fechas y horas se vuelve m谩s complejo al tratar con zonas horarias. Todos los ejemplos anteriores que hemos discutido son ingenuos datetime objetos, es decir, estos objetos no contienen datos relacionados con la zona horaria. los datetime el objeto tiene una variable que contiene la informaci贸n de la zona horaria, tzinfo.

    import datetime as dt
    
    dtime = dt.datetime.now()
    
    print(dtime)
    print(dtime.tzinfo)
    

    Este c贸digo imprimir谩:

    $ python3 datetime-tzinfo-1.py
    2018-06-29 22:16:36.132767
    None
    

    La salida de tzinfo es None ya que es un ingenuo datetime objeto. Para la conversi贸n de zona horaria, una biblioteca llamada pytz est谩 disponible para Python. Puede instalarlo como se describe en estas instrucciones. Ahora, usemos el pytz biblioteca para convertir la marca de tiempo anterior a UTC.

    import datetime as dt
    import pytz
    
    dtime = dt.datetime.now(pytz.utc)
    
    print(dtime)
    print(dtime.tzinfo)
    

    Salida:

    $ python3 datetime-tzinfo-2.py
    2018-06-29 17:08:00.586525+00:00
    UTC
    

    +00:00 es la diferencia entre la hora mostrada y la hora UTC. En este ejemplo, el valor de tzinfo pasa a ser UTC tambi茅n, de ah铆 el 00:00 compensar. En este caso, el datetime El objeto es un objeto que reconoce la zona horaria.

    De manera similar, podemos convertir cadenas de fecha y hora a cualquier otra zona horaria. Por ejemplo, podemos convertir la cadena “2018-06-29 17: 08: 00.586525 + 00: 00” a la zona horaria “America / New_York”, como se muestra a continuaci贸n:

    import datetime as dt
    import pytz
    
    date_time_str="2018-06-29 17:08:00"
    date_time_obj = dt.datetime.strptime(date_time_str, '%Y-%m-%d %H:%M:%S')
    
    timezone = pytz.timezone('America/New_York')
    timezone_date_time_obj = timezone.localize(date_time_obj)
    
    print(timezone_date_time_obj)
    print(timezone_date_time_obj.tzinfo)
    

    Salida:

    $ python3 datetime-tzinfo-3.py
    2018-06-29 17:08:00-04:00
    America/New_York
    

    Primero, hemos convertido la cadena en un datetime objeto, date_time_obj. Luego lo convertimos a una zona horaria habilitada datetime objeto, timezone_date_time_obj. Dado que hemos establecido la zona horaria como “America / New_York”, la hora de salida muestra que est谩 4 horas por detr谩s de la hora UTC. Puedes comprobar esta p谩gina de Wikipedia para encontrar la lista completa de zonas horarias disponibles.

    Conversi贸n de zonas horarias

    Podemos convertir la zona horaria de un datetime objeto de una regi贸n a otra, como se muestra en el siguiente ejemplo:

    import datetime as dt
    import pytz
    
    timezone_nw = pytz.timezone('America/New_York')
    nw_datetime_obj = dt.datetime.now(timezone_nw)
    
    timezone_london = pytz.timezone('Europe/London')
    london_datetime_obj = nw_datetime_obj.astimezone(timezone_london)
    
    
    print('America/New_York:', nw_datetime_obj)
    print('Europe/London:', london_datetime_obj)
    

    Primero, creamos un objeto de fecha y hora con la hora actual y lo configuramos como la zona horaria “Am茅rica / New_York”. Luego usando el astimezone() m茅todo, hemos convertido este datetime a la zona horaria “Europa / Londres”. Ambos datetimes imprimir谩 diferentes valores como:

    $ python3 datetime-tzinfo-4.py
    America/New_York: 2018-06-29 22:21:41.349491-04:00
    Europe/London: 2018-06-30 03:21:41.349491+01:00
    

    Como era de esperar, las fechas y horas son diferentes, ya que tienen una diferencia de aproximadamente 5 horas.

    Uso de bibliotecas de terceros

    Python datetime m贸dulo puede convertir todos los diferentes tipos de cadenas en un datetime objeto. Pero el problema principal es que para hacer esto necesita crear la cadena de c贸digo de formato adecuada que strptime puede entender. La creaci贸n de esta cadena lleva tiempo y dificulta la lectura del c贸digo. En cambio, podemos usar otras bibliotecas de terceros para hacerlo m谩s f谩cil.

    En algunos casos, estas bibliotecas de terceros tambi茅n tienen un mejor soporte integrado para manipular y comparar fechas y horas, y algunas incluso tienen zonas horarias integradas, por lo que no es necesario incluir un paquete adicional.

    Echemos un vistazo a algunas de estas bibliotecas en las siguientes secciones.

    dateutil

    los m贸dulo dateutil es una extensi贸n de la datetime m贸dulo. Una ventaja es que no necesitamos pasar ning煤n c贸digo de an谩lisis para analizar una cadena. Por ejemplo:

    from dateutil.parser import parse
    
    datetime = parse('2018-06-29 22:21:41')
    
    print(datetime)
    

    Esta parse La funci贸n analizar谩 la cadena autom谩ticamente y la almacenar谩 en el datetime variable. El an谩lisis se realiza autom谩ticamente. No es necesario que menciones ninguna cadena de formato. Intentemos analizar diferentes tipos de cadenas usando dateutil:

    from dateutil.parser import parse
    
    date_array = [
        '2018-06-29 08:15:27.243860',
        'Jun 28 2018 7:40AM',
        'Jun 28 2018 at 7:40AM',
        'September 18, 2017, 22:19:55',
        'Sun, 05/12/1999, 12:30PM',
        'Mon, 21 March, 2015',
        '2018-03-12T10:12:45Z',
        '2018-06-29 17:08:00.586525+00:00',
        '2018-06-29 17:08:00.586525+05:00',
        'Tuesday , 6th September, 2017 at 4:30pm'
    ]
    
    for date in date_array:
        print('Parsing: ' + date)
        dt = parse(date)
        print(dt.date())
        print(dt.time())
        print(dt.tzinfo)
        print('n')
    

    Salida:

    $ python3 dateutil-1.py
    Parsing: 2018-06-29 08:15:27.243860
    2018-06-29
    08:15:27.243860
    None
    
    Parsing: Jun 28 2018 7:40AM
    2018-06-28
    07:40:00
    None
    
    Parsing: Jun 28 2018 at 7:40AM
    2018-06-28
    07:40:00
    None
    
    Parsing: September 18, 2017, 22:19:55
    2017-09-18
    22:19:55
    None
    
    Parsing: Sun, 05/12/1999, 12:30PM
    1999-05-12
    12:30:00
    None
    
    Parsing: Mon, 21 March, 2015
    2015-03-21
    00:00:00
    None
    
    Parsing: 2018-03-12T10:12:45Z
    2018-03-12
    10:12:45
    tzutc()
    
    Parsing: 2018-06-29 17:08:00.586525+00:00
    2018-06-29
    17:08:00.586525
    tzutc()
    
    Parsing: 2018-06-29 17:08:00.586525+05:00
    2018-06-29
    17:08:00.586525
    tzoffset(None, 18000)
    
    Parsing: Tuesday , 6th September, 2017 at 4:30pm
    2017-09-06
    16:30:00
    None
    

    Puede ver que casi cualquier tipo de cadena se puede analizar f谩cilmente utilizando el dateutil m贸dulo.

    Si bien esto es conveniente, recuerde que tener que predecir el formato hace que el c贸digo sea mucho m谩s lento, por lo que si su c贸digo requiere un alto rendimiento, entonces este podr铆a no ser el enfoque correcto para su aplicaci贸n.

    maya

    maya tambi茅n hace que sea muy f谩cil analizar una cadena y cambiar las zonas horarias. Aqu铆 se muestran algunos ejemplos simples:

    import maya
    
    dt = maya.parse('2018-04-29T17:45:25Z').datetime()
    print(dt.date())
    print(dt.time())
    print(dt.tzinfo)
    

    Salida:

    $ python3 maya-1.py
    2018-04-29
    17:45:25
    UTC
    

    Para convertir la hora a una zona horaria diferente:

    import maya
    
    dt = maya.parse('2018-04-29T17:45:25Z').datetime(to_timezone="America/New_York", naive=False)
    print(dt.date())
    print(dt.time())
    print(dt.tzinfo)
    

    Salida:

    $ python3 maya-2.py
    2018-04-29
    13:45:25
    America/New_York
    

    驴No es tan f谩cil de usar? Vamos a probar maya con el mismo conjunto de cadenas que hemos usado con dateutil:

    import maya
    
    date_array = [
        '2018-06-29 08:15:27.243860',
        'Jun 28 2018 7:40AM',
        'Jun 28 2018 at 7:40AM',
        'September 18, 2017, 22:19:55',
        'Sun, 05/12/1999, 12:30PM',
        'Mon, 21 March, 2015',
        '2018-03-12T10:12:45Z',
        '2018-06-29 17:08:00.586525+00:00',
        '2018-06-29 17:08:00.586525+05:00',
        'Tuesday , 6th September, 2017 at 4:30pm'
    ]
    
    for date in date_array:
        print('Parsing: ' + date)
        dt = maya.parse(date).datetime()
        print(dt)
        print(dt.date())
        print(dt.time())
        print(dt.tzinfo)
    

    Salida:

    $ python3 maya-3.py
    Parsing: 2018-06-29 08:15:27.243860
    2018-06-29 08:15:27.243860+00:00
    2018-06-29
    08:15:27.243860
    UTC
    
    Parsing: Jun 28 2018 7:40AM
    2018-06-28 07:40:00+00:00
    2018-06-28
    07:40:00
    UTC
    
    Parsing: Jun 28 2018 at 7:40AM
    2018-06-28 07:40:00+00:00
    2018-06-28
    07:40:00
    UTC
    
    Parsing: September 18, 2017, 22:19:55
    2017-09-18 22:19:55+00:00
    2017-09-18
    22:19:55
    UTC
    
    Parsing: Sun, 05/12/1999, 12:30PM
    1999-05-12 12:30:00+00:00
    1999-05-12
    12:30:00
    UTC
    
    Parsing: Mon, 21 March, 2015
    2015-03-21 00:00:00+00:00
    2015-03-21
    00:00:00
    UTC
    
    Parsing: 2018-03-12T10:12:45Z
    2018-03-12 10:12:45+00:00
    2018-03-12
    10:12:45
    UTC
    
    Parsing: 2018-06-29 17:08:00.586525+00:00
    2018-06-29 17:08:00.586525+00:00
    2018-06-29
    17:08:00.586525
    UTC
    
    Parsing: 2018-06-29 17:08:00.586525+05:00
    2018-06-29 12:08:00.586525+00:00
    2018-06-29
    12:08:00.586525
    UTC
    
    Parsing: Tuesday , 6th September, 2017 at 4:30pm
    2017-09-06 16:30:00+00:00
    2017-09-06
    16:30:00
    UTC
    

    Como puede ver, todos los formatos de fecha se analizaron correctamente.

    驴Pero not贸 la diferencia? Si no proporcionamos la informaci贸n de la zona horaria, la convierte autom谩ticamente a UTC. Por lo tanto, es importante tener en cuenta que debemos proporcionar to_timezone y naive par谩metros si la hora no est谩 en UTC.

    Flecha

    Flecha es otra biblioteca para lidiar con la fecha y hora en Python. Y como antes con maya, tambi茅n determina el formato de fecha y hora autom谩ticamente. Una vez interpretado, devuelve un Python datetime objeto del arrow objeto.

    Probemos esto con la misma cadena de ejemplo que hemos usado para maya:

    import arrow
    
    dt = arrow.get('2018-04-29T17:45:25Z')
    print(dt.date())
    print(dt.time())
    print(dt.tzinfo)
    

    Salida:

    $ python3 arrow-1.py
    2018-04-29
    17:45:25
    tzutc()
    

    Y as铆 es como puedes usar arrow para convertir zonas horarias usando el to m茅todo:

    import arrow
    
    dt = arrow.get('2018-04-29T17:45:25Z').to('America/New_York')
    print(dt)
    print(dt.date())
    print(dt.time())
    

    Salida:

    $ python3 arrow-2.py
    2018-04-29T13:45:25-04:00
    2018-04-29
    13:45:25
    

    Como puede ver, la cadena de fecha y hora se convierte a la regi贸n “America / New_York”.

    Ahora, usemos nuevamente el mismo conjunto de cadenas que hemos usado anteriormente:

    import arrow
    
    date_array = [
        '2018-06-29 08:15:27.243860',
        #'Jun 28 2018 7:40AM',
        #'Jun 28 2018 at 7:40AM',
        #'September 18, 2017, 22:19:55',
        #'Sun, 05/12/1999, 12:30PM',
        #'Mon, 21 March, 2015',
        '2018-03-12T10:12:45Z',
        '2018-06-29 17:08:00.586525+00:00',
        '2018-06-29 17:08:00.586525+05:00',
        #'Tuesday , 6th September, 2017 at 4:30pm'
    ]
    
    for date in date_array:
        dt = arrow.get(date)
        print('Parsing: ' + date)
        print(dt)
        print(dt.date())
        print(dt.time())
        print(dt.tzinfo)
    

    Este c贸digo fallar谩 para las cadenas de fecha y hora que se han comentado, que es m谩s de la mitad de nuestros ejemplos. La salida para otras cadenas ser谩:

    $ python3 arrow-3.py
    Parsing: 2018-06-29 08:15:27.243860
    2018-06-29T08:15:27.243860+00:00
    2018-06-29
    08:15:27.243860
    tzutc()
    
    Parsing: 2018-03-12T10:12:45Z
    2018-03-12T10:12:45+00:00
    2018-03-12
    10:12:45
    tzutc()
    
    Parsing: 2018-06-29 17:08:00.586525+00:00
    2018-06-29T17:08:00.586525+00:00
    2018-06-29
    17:08:00.586525
    tzoffset(None, 0)
    
    Parsing: 2018-06-29 17:08:00.586525+05:00
    2018-06-29T17:08:00.586525+05:00
    2018-06-29
    17:08:00.586525
    tzoffset(None, 18000)
    

    Para analizar correctamente las cadenas de fecha y hora que he comentado, deber谩 pasar los tokens de formato correspondientes para dar a la biblioteca pistas sobre c贸mo analizarlo. Por ejemplo, “MMM” para el nombre de los meses, como “Ene, Feb, Mar”, etc. Puede marcar esta gu铆a para todos los tokens disponibles.

    Conclusi贸n

    En este art铆culo hemos mostrado diferentes formas de analizar una cadena a un datetime objeto en Python. Puede optar por el Python predeterminado datetime library o cualquiera de las bibliotecas de terceros mencionadas en este art铆culo, entre muchas otras.

    El principal problema con el defecto datetime paquete es que necesitamos especificar el c贸digo de an谩lisis manualmente para casi todos los formatos de cadena de fecha y hora. Por lo tanto, si su formato de cadena cambia en el futuro, es probable que tambi茅n tenga que cambiar su c贸digo. Pero muchas bibliotecas de terceros, como las que se mencionan aqu铆, lo manejan autom谩ticamente.

    Otro problema al que nos enfrentamos es el de las zonas horarias. La mejor manera de manejarlos es siempre almacenar la hora en su base de datos como formato UTC y luego convertirla a la zona horaria local del usuario cuando sea necesario.

    Estas bibliotecas no solo son buenas para analizar cadenas, sino que tambi茅n pueden usarse para muchos tipos diferentes de operaciones relacionadas con la fecha y la hora. Te animo a que revises los documentos para conocer las funcionalidades en detalle.

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *