Analizar cadenas de fecha y hora con parsedatetime en Python

En este tutorial, veremos cómo analizar cadenas de fecha y hora en Python con parsedatetime, incluidas zonas horarias y locales, con ejemplos.

Introducción

En este tutorial, veremos cómo analizar Datetime con parsedatetime en Python.

Para usar el paquete parsedatetime, primero debemos instalarlo usando pip:

1
$ pip install parsedatetime

Si pip install parsedatetime falla, el paquete también es de código abierto y está disponible en Github.

Convertir cadena en objeto Datetime de Python con parsedatetime

La primera y más común forma de usar parsedatetime es analizar una cadena en un objeto datetime. Primero, querrá importar la biblioteca parsedatetime e instanciar un objeto Calendar, que realiza la entrada, el análisis y la manipulación de fechas reales:

1
2
import parsedatetime
calendar = parsedatetime.Calendar()

Ahora podemos llamar al método parse() de la instancia calendar con una cadena como argumento. Puede poner cadenas regulares con formato de fecha y hora, como 1-1-2021 o valores legibles por humanos como mañana, ayer, próximo año, la semana pasada, mañana almorzamos, etc. ... También podemos usar estructuras 'End of Day' con tomorrow eod

Vamos a convertir una cadena de fecha y hora y legible por humanos en un objeto datetime usando parsedatetime:

1
2
3
4
5
6
7
import parsedatetime
from datetime import datetime

calendar = parsedatetime.Calendar()

print(calendar.parse('tomorrow'))
print(calendar.parse('1-1-2021'))

Esto da como resultado dos tuplas impresas:

1
2
(time.struct_time(tm_year=2021, tm_mon=3, tm_mday=19, tm_hour=9, tm_min=0, tm_sec=0, tm_wday=4, tm_yday=78, tm_isdst=-1), 1)
(time.struct_time(tm_year=2021, tm_mon=1, tm_mday=1, tm_hour=18, tm_min=5, tm_sec=14, tm_wday=3, tm_yday=77, tm_isdst=0), 1)

Esto no es muy legible por humanos... La tupla devuelta para cada conversión consiste en el objeto struct_time, que contiene información como el año, mes, día del mes, etc. El segundo valor es el *código de estado * - un número entero que indica cómo fue la conversión.

0 significa análisis fallido, 1 significa análisis exitoso a una fecha, 2 significa análisis exitoso a una hora y 3 significa análisis exitoso a una fechahora.

Analicemos esta salida:

1
2
print(calendar.parse('tomorrow')[0].tm_mday)
print(calendar.parse('1-1-2021')[0].tm_mday)

Este código da como resultado:

1
2
19
1

Por otra parte, aquí solo obtenemos el día del mes. Por lo general, nos gustaría generar algo similar a un formato YYYY-mm-dd HH: mm: ss, o cualquier variación de eso.

Afortunadamente, podemos usar fácilmente el resultado de time.struct_time y generar un datetime normal de Python con él:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import parsedatetime
from datetime import datetime

calendar = parsedatetime.Calendar()

time_structure_tomorrow, parse_status_tomorrow = calendar.parse('tomorrow')
time_structure_2021, parse_status_2021 = calendar.parse('1-1-2021')

print(datetime(*time_structure_tomorrow[:6]))
print(datetime(*time_structure_2021[:6]))

El constructor datetime() no necesita toda la información de la estructura de tiempo provista por parsedatetime, así que la dividimos.

Este código da como resultado:

1
2
2021-03-19 09:00:00
2021-01-01 18:11:06

Tenga en cuenta que la fecha y hora del 1 de enero tuvo en cuenta la hora de ejecución.

Manejo de zonas horarias

A veces, es posible que su aplicación deba tener en cuenta las zonas horarias de sus usuarios finales. Para el soporte de zona horaria, generalmente usamos el paquete Pytz, aunque también puede usar otros paquetes.

Instalemos Pytz a través de pip:

1
$ pip install pytz

Ahora, podemos importar los paquetes parsedatetime y pytz a un script y crear una instancia estándar de Calendar:

1
2
3
4
5
import parsedatetime
import pytz
from pytz import timezone

calendar = parsedatetime.Calendar()

Echemos un vistazo a las zonas horarias admitidas, imprimiendo all_timezones:

1
print(pytz.all_timezones)

Este código dará como resultado una enorme lista de todas las zonas horarias disponibles:

1
['Africa/Abidjan', 'Africa/Accra', 'Africa/Addis_Ababa', 'Africa/Algiers', ...]

Elijamos uno de estos, como el primero, y pasémoslo como el argumento tzinfo de la función parseDT() de Calendar. Aparte de eso, querremos proporcionar un argumento datetimeString, que es la cadena real que queremos analizar:

1
datetime_object, status = calendar.parseDT(datetimeString='tomorrow', tzinfo=timezone('Africa/Abidjan'))

Este método devuelve una tupla de un objeto Datetime y el código de estado de la conversión, que es un número entero: 1 significa "exitoso" y 0 significa "no tuvo éxito".

Avancemos e imprimamos datetime_object:

1
print(datetime_object)

Este código da como resultado:

1
2021-03-16 09:00:00+00:00

Calendar.parseDate()

Mientras que Calendar.parse() es un método de análisis de nivel general, que devuelve una tupla con el código de estado y time.struct_time, el método parseDate() es un método dedicado a cadenas de fechas de formato corto, y simplemente devuelve un resultado legible por humanos:

1
2
3
4
5
import parsedatetime
calendar = parsedatetime.Calendar()

result = calendar.parseDate('5/5/91')
print(result)

El resultado ahora contiene el valor struct_time calculado de la fecha que hemos pasado:

1
(1991, 5, 5, 14, 31, 18, 0, 74, 0)

Pero, ¿qué hacemos cuando queremos analizar el 5 de mayo de 2077? Podemos intentar ejecutar el siguiente código:

1
2
3
4
import parsedatetime
calendar = parsedatetime.Calendar()
result = calendar.parseDate('5/5/77')
print(result)

Sin embargo, este código dará como resultado:

1
(1977, 5, 5, 14, 36, 21, 0, 74, 0)

Calendar.parseDate() confundió la fecha abreviada con un 1977 más realista. Podemos solucionar esto de dos formas:

  • Simplemente especifique el año completo - 2077:
1
2
3
4
import parsedatetime
calendar = parsedatetime.Calendar()
result = calendar.parseDate('5/5/2077')
print(result)
  • Usa una Época de cumpleaños:
1
2
3
4
5
6
7
8
import parsedatetime
constants = parsedatetime.Constants()
constants.BirthdayEpoch = 80

# Pass our new constants to the Calendar
calendar = parsedatetime.Calendar(constants)
result = calendar.parseDate('5/5/77')
print(result)

Este código dará como resultado:

1
(2077, 5, 5, 14, 39, 47, 0, 74, 0)

Puede acceder a los contenidos de la biblioteca parsedatetime a través del objeto Constants. Aquí, hemos configurado birthdayepoch en 80.

birthdayepoch controla cómo el paquete maneja los años de dos dígitos, como 77. Si el valor analizado es menor que el valor que hemos establecido para birthdayepoch, agregará el valor analizado a 2000. Dado que configuramos birthdayepoch en 80 y analizamos 77, lo convierte en 2077.

De lo contrario, agregará el valor analizado a 1900.

Calendar.parseDateText()

Otra alternativa para lidiar con el problema de las fechas abreviadas erróneas es, bueno, usar fechas largas. Para fechas largas, puedes usar el método parseDateText():

1
2
3
4
import parsedatetime

result2 = calendar.parseDateText('May 5th, 1991')
print(result2)

Este código dará como resultado:

1
(1991, 5, 5, 14, 31, 46, 0, 74, 0)

Uso de configuraciones regionales

Finalmente, podemos usar parsedatetime con información local. La información de configuración regional proviene de PyUCI o de la clase Constants utilizada anteriormente.

La clase interna Constants tiene muchos atributos, al igual que el atributo birthdayepoch. Dos de estos son localeID y userPyICU.

Intentemos configurar localeId en español y configuremos usePyICU en False ya que no lo usaremos:

1
2
3
4
5
6
import parsedatetime

constants = parsedatetime.Constants(localeID='es', usePyICU=False)
calendar = parsedatetime.Calendar(constants)
result, code = calendar.parse('Marzo 28')
print(result)

Esto resulta en:

1
(time.struct_time(tm_year=2021, tm_mon=3, tm_mday=28, tm_hour=15, tm_min=0, tm_sec=5, tm_wday=0, tm_yday=74, tm_isdst=0), 1)

El método devuelve un struct_time, por lo que podemos convertirlo fácilmente en un datetime:

1
print(datetime(*result[:6]))

Esto resulta en:

1
2021-03-28 22:08:40

Conclusión

En este tutorial, hemos repasado varias formas de analizar datetime usando el paquete parsedatetime en Python.

Repasamos la conversión entre cadenas y objetos datetime a través de parsedatetime, así como el manejo de zonas horarias con pytz y locales, usando la instancia Constants de la biblioteca parsedatetime.