Trabajando con Datetime en Python con Arrow

Arrow es un módulo de Python para trabajar con fecha y hora. Dado que hay varios módulos que hacen esto, sobre todo el módulo de fecha y hora incorporado, ¿qué hace...

Introducción

Flecha es un módulo de Python para trabajar con fecha y hora. Dado que hay varios módulos que hacen esto, más notablemente el módulo incorporado datetime, ¿qué hace que Arrow sea diferente?

En particular, la biblioteca está inspirada en Momento.js, una biblioteca de JavaScript que anula la implementación predeterminada de la API de fecha y hora.

En esta guía, veremos algunas características clave de Arrow para ver cómo maneja ciertas tareas comunes.

Primero, sigamos adelante e instálelo:

1
$ pip install Arrow

La clase Arrow

La clase Arrow es una implementación de la interfaz datetime, con funcionalidades adicionales. Además, es consciente de la zona horaria de forma predeterminada; sin embargo, hablaremos de esto un poco más tarde.

Puede crear fácilmente una nueva instancia de Arrow proporcionando a su constructor algunos argumentos:

1
2
3
import arrow
arrow_object = arrow.Arrow(2021, 1, 1)
print(arrow_object)

Esto resulta en:

1
2021-01-01T00:00:00+00:00

También puede proporcionar las horas, minutos y segundos a través del constructor:

1
2
3
import arrow
arrow_object = arrow.Arrow(2021, 1, 1, 14, 30, 21)
print(arrow_object)

Esto resulta en:

1
2021-01-01T14:30:21+00:00

Soporte de conversión con flecha

Analizar una fecha y hora de una cadena es un proceso sencillo con Arrow: simplemente usa el método get() y le proporcionas un formato de cadena válido. Además, Arrow te permite convertir sin esfuerzo entre su propia implementación de la clase datetime y el objeto datetime incorporado.

Convertir cadena a fechahora con flecha

Si una cadena ya tiene el formato ISO 8601 (YYYY-MM-DDTHH:MM:SS.mmmmmm), se puede pasar directamente al método get():

1
2
3
import arrow
datetime = arrow.get('2021/03/30 12:05')
print(datetime)

Esto imprimirá la instancia de Arrow, que es la propia implementación de Arrow de la interfaz datetime:

1
<Arrow [2021-03-30T12:05:00+00:00]>

Sin embargo, en la práctica, es poco probable que usemos cadenas formateadas correctamente, siguiendo la especificación ISO.

Afortunadamente, todavía podemos analizar cadenas que no se adhieren a las convenciones, usando tokens de formato de flecha correctos. Estos están predefinidos y le dan a Arrow la información necesaria para analizar la cadena correctamente:

1
2
3
import arrow
datetime = arrow.get('March 30 2021 12:05', 'MMMM DD YYYY HH:mm')
print(datetime)

Aquí, le hemos dicho efectivamente a Arrow cuál es el formato. Mapea los tokens de formato proporcionados con la cadena que nos gustaría analizar y construye un objeto Flecha basado en esa información. Ejecutar esto da como resultado:

1
<Arrow [2021-03-30T12:05:00+00:00]>

Convertir entre objetos Arrow y datetime {#convert betweenarrowanddatetimeobjects}

Hasta ahora, hemos estado trabajando con instancias de Arrow. Sin embargo, muchas aplicaciones y bibliotecas requieren explícitamente que uses un objeto datetime. La conversión entre estos dos formatos es crucial.

Echemos un vistazo al tipo() de nuestra variable:

1
type(datetime)

Producción:

1
arrow.arrow.Arrow

Para convertir esto en una instancia datetime, simplemente extraemos el campo datetime del objeto Arrow:

1
2
datetime = datetime.datetime
print(datetime)

Esto da como resultado una instancia datetime consciente de la zona horaria:

1
datetime.datetime(2021, 3, 12, 12, 5, tzinfo=tzutc())

Aunque no hemos especificado la zona horaria al crear el objeto Arrow original, el objeto datetime tiene el tzinfo predeterminado en UTC. Nos referiremos a esto en la siguiente sección, cuando analicemos más detalladamente el manejo de las zonas horarias.

Por ahora, podemos confirmar que es de hecho un tipo de objeto datetime:

1
type(now)

Esto resulta en;

1
datetime.datetime

De manera similar, puede convertir fácilmente objetos datetime en objetos Arrow, utilizando la función fromdatetime():

1
2
3
datetime = datetime.datetime(2021, 1, 1, 0, 0)
arrow_object = arrow.Arrow.fromdatetime(datetime)
print(arrow_object)

Esto resulta en:

1
2021-01-01T00:00:00+00:00

Manejo de zonas horarias {#tratamiento con zonas horarias}

Uno de los principales problemas con el módulo datetime es la forma en que maneja las zonas horarias. Se considera timezone-naive, lo que significa que no contiene datos relacionados con la zona horaria. Arrow, por otro lado, contiene un parámetro tzinfo para cada instancia, que puede configurar a través del constructor o mediante métodos. El valor predeterminado de tzinfo es UTC, independientemente de la ubicación del usuario.

En términos prácticos, esto significa que con datetime, un usuario en Hong Kong estaría trabajando en la hora local de Hong Kong, mientras que un usuario en el Reino Unido estaría trabajando en la hora local del Reino Unido, a menos que se especifique lo contrario:

1
2
import datetime
datetime.datetime.now()

El resultado para el usuario basado en Hong Kong sería:

1
datetime.datetime(2021, 3, 31, 00, 35, 08, 114203)

Mientras que alguien con sede en el Reino Unido vería:

1
datetime.datetime(2021, 3, 30, 17, 35, 25, 119213)

Tener una zona horaria predeterminada estándar es cada vez más importante con el aumento del trabajo remoto y la globalización de los proyectos. Tener que establecer explícitamente las zonas horarias para los objetos datetime se vuelve obsoleto rápidamente. Arrow automatiza este proceso, en una zona horaria única, unificada y predeterminada. Puede configurarlo en otras zonas horarias, por supuesto, o incluso en las locales.

Independientemente de la ubicación geográfica del usuario, las siguientes líneas de código darán el mismo resultado:

1
arrow.now()

Producción:

1
<Arrow [2021-03-30T17:37:28.374335+01:00]>

Podemos confirmar que esto corresponde a la hora UTC:

1
arrow.utcnow()

Producción:

1
<Arrow [2021-03-30T16:37:59.721766+00:00]>

Podemos establecer zonas horarias en la instancia de Arrow simplemente pasando la cadena de zona horaria en su constructor:

1
arrow.now('US/Pacific)

Esto funciona junto con otros parámetros que hemos usado antes. Establecer una zona horaria mientras se construye una instancia de Arrow funciona tanto para convertir cadenas y objetos datetime como para llamar explícitamente al constructor:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import arrow
import datetime as datetime


date = '2021.01.01 00:00'
datetime = datetime.datetime(2021, 1, 1, 0, 0)

arrow_1 = arrow.Arrow(2021, 1, 1, 0, 0, tzinfo='US/Pacific')
arrow_2 = arrow.get(date, tzinfo='US/Pacific')
arrow_3 = arrow.Arrow.fromdatetime(datetime, tzinfo='US/Pacific')

print(arrow_1)
print(arrow_2)
print(arrow_3)

Ahora, estas instancias de ‘Arrow’ se establecerán en la zona horaria ‘EE. UU./Pacífico’ y se configurarán para el 1 de enero de 2021:

1
2
3
2021-01-01T00:00:00-08:00
2021-01-01T00:00:00-08:00
2021-01-01T00:00:00-08:00

Como puede ver, los objetos ahora tienen un sufijo “-08:00”, ya que la zona horaria “EE. UU./Pacífico” está 8 horas por detrás de UTC.

También puede extraer las versiones ingenuas de estas fechas y horas llamando a su campo ingenuo:

1
2
3
print(arrow_1.naive)
print(arrow_2.naive)
print(arrow_3.naive)

Esto no los despojará de su conciencia de la zona horaria, lo que resultará en lo que esperarías cuando trabajas con objetos ingenuos datetime:

1
2
3
2021-01-01 00:00:00
2021-01-01 00:00:00
2021-01-01 00:00:00

Conversión entre zonas horarias con flecha {#converting betweentimezoneswitharrow}

Otra área que vale la pena ver es cómo podemos convertir entre diferentes zonas horarias con Arrow usando el método to(). Si bien Arrow es totalmente compatible con los módulos de zona horaria, no es necesario importar ningún módulo adicional para la conversión de zona horaria.

Para empezar podemos obtener la hora actual y asignarla a una variable:

1
2
utc=arrow.now()
print(utc)
1
<Arrow [2021-03-30T17:41:08.765166+01:00]>

Ahora, vamos a convertir este objeto a otra zona horaria:

1
utc.to('US/Pacific')

Esto resulta en:

1
<Arrow [2021-03-30T09:41:08.765166-07:00]>

O la hora en Hong Kong:

1
utc.to('Asia/Hong_Kong')
1
<Arrow [2021-03-30T09:41:08.765166-07:00]>

Incluso podemos especificar la diferencia horaria con el número de horas:

1
utc.to('-05:00')

Esta es una forma mucho más intuitiva de convertir entre zonas horarias, especialmente si no tiene a mano una lista de los nombres apropiados:

1
<Arrow [2021-03-30T11:41:08.765166-05:00]>

Fechas humanizantes y cambiantes {#fechas humanizantes y cambiantes}

A menudo, cuando se trata de períodos de tiempo, en realidad no necesitamos una fecha. Cuando hablamos con colegas, decimos:

"Fui de compras ayer".

No:

"Fui de compras el 03/12/2021", que es el día anterior al 04/12/2021", que es el día en este momento.

En muchos casos, es posible que desee humanizar las fechas, como anotar cuándo llegó una notificación, se envió un correo electrónico o cuándo alguien realizó una determinada acción registrada. Afortunadamente, Arrow nos permite humanizar fácilmente cualquier fecha a través de la función humanize().

Esta función funciona de maravilla con la función shift(), que puede cambiar las fechas en 0...n días. Es posible que desee crear un sistema que notifique a una persona cuando se acerca una fecha determinada, en lenguaje humano:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import arrow

now = arrow.now()
tomorrow = now.shift(days=1)
yesterday = now.shift(days=-1)
next_week = now.shift(days=7)
notification = now.shift(days=-2, hours=-5, minutes=-7)

print(now.humanize())
print(tomorrow.humanize())
print(yesterday.humanize())
print(next_week.humanize())
print(notification.humanize(granularity=['day', 'hour', 'minute']))

Aquí, hemos creado un objeto Flecha usando la función ahora(). Luego, hemos creado una serie de objetos desplazando los valores hacia arriba o hacia abajo. La función shift() acepta argumentos como años, meses, días, horas, minutos y segundos. Hemos creado un objeto mañana y ayer al subir y bajar un día (no en el lugar), y un objeto para próxima_semana y un objeto arbitrario de notificación que sucedió 2 días, 5 horas y hace 7 minutos.

Finalmente, al humanizar, puede especificar la “granularidad”, lo que le permite a Arrow saber cuán detallado debe ser cuando se trata de informar el tiempo en lenguaje humano. De forma predeterminada, establecerá la granularidad en “día” y/o “semana”, según el intervalo de tiempo. En nuestro caso, hemos dejado la configuración predeterminada activada, a excepción del objeto final en el que queremos específicamente un poco de granularidad más fina:

1
2
3
4
5
just now
in a day
a day ago
in a week
2 days 5 hours and 7 minutes ago

Esta es una forma muy intuitiva y humana de representar fechas para su usuario, como contar los días hasta un evento o contar los días desde un evento.

Ventajas de usar Arrow

Las ventajas de usar Arrow se podrían resumir con las declaraciones oficiales de su documentación:

Enfoque sensato y amigable con el ser humano.

Compatible con muchos escenarios de creación comunes.

Ayudarlo a trabajar con fechas y horas con menos importaciones y mucho menos código.

En estos, parece tener éxito, y Arrow supera los principales problemas con la biblioteca datetime. Por lo que hemos visto en nuestros ejemplos anteriores, Arrow es sin duda una mejora en términos de:

  • Reducción de la necesidad de importar múltiples módulos
  • Trabajar en un solo tipo de datos (Flecha)
  • Ser consciente de la zona horaria
  • Simplificación de la creación de las funciones de fecha y hora más utilizadas
  • Fácil conversión entre varios tipos
  • Funciones útiles de humanización.
  • Cambiar fácilmente los valores al pasado y al futuro

Conclusión

En esta guía, nos hemos centrado en algunos de los beneficios de usar la biblioteca Arrow para trabajar con fecha y hora en Python. Está inspirado en Moment.js y ofrece soluciones a algunos de los problemas conocidos de la biblioteca datetime.

Sin embargo, vale la pena tener en cuenta que hay muchos otros módulos de fecha y hora disponibles. También vale la pena señalar que ser un módulo incorporado le da a datetime la ventaja de necesitar que los usuarios busquen de manera proactiva reemplazarlo.

Todo se reduce a la importancia del elemento de fecha y hora para su proyecto y su código.

Licensed under CC BY-NC-SA 4.0