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 *