¿Cuál es la diferencia entre "datetime.timedelta" y "dateutil.relativedelta.relativedelta" cuando se trabaja solo con días?

90

Cuál es la diferencia entre datetime.timedelta (de la biblioteca estándar de Python) y dateutil.relativedelta.relativedeltacuando se trabaja solo con días?

Hasta donde yo entiendo, timedelta solo admite días (y semanas), mientras que relativedeltaagrega soporte para períodos definidos en términos de años, meses, semanas o días, además de definir valores absolutos para año, mes o día. (recuerde, para los propósitos de esta pregunta, no tengo que preocuparme por horas, minutos o segundos)

Teniendo en cuenta que solo trabajo con datetime.dateobjetos y solo me interesan los períodos definidos por el número de días, ¿cuál es la diferencia entre timedeltay relativedelta? ¿Hay alguna diferencia?

from datetime import date, timedelta
from dateutil.relativedelta import relativedelta

i = -1  # This could have been any integer, positive or negative
someday = date.today()
# Is there any difference between these two lines?
otherday = someday + timedelta(days=i)
otherday = someday + relativedelta(days=i)
Denilson Sá Maia
fuente
3
Si solo está interesado en deltas en días entre fechas, simplemente use la biblioteca estándar dateime.timedeltaque logrará lo que desea y evitará la dependencia del dateutilpaquete externo .
Pedro Romano
Vale la pena decir que, además de ahorrar una dependencia adicional, calcular deltas en días entre fechas es varias veces más rápido con timedelta que con relativadelta. (~ 10 veces)
Julien B.

Respuestas:

76

dateutil es un paquete de extensión para el estándar python datetime módulo . Como usted dice, proporciona una funcionalidad adicional, como timedeltas que se expresan en unidades mayores a un día.

Esto es útil si tiene que hacer preguntas como ¿cuántos meses puedo ahorrar antes de que llegue el cumpleaños de mi novia o cuál es el último viernes del mes? Esto oculta cálculos complejos causados ​​por las diferentes duraciones de los meses o días adicionales en los años bisiestos.

En tu caso, solo te interesa la cantidad de días. Por lo tanto, es mejor usarlo timedeltaya que esto evita una dependencia adicional del dateutilpaquete.

Hans entonces
fuente
32

A relativedeltatiene muchos más parámetros que a timedelta:

Definition:   relativedelta.relativedelta(self, dt1=None, dt2=None,
years=0, months=0, days=0, leapdays=0, weeks=0, hours=0, minutes=0,
seconds=0, microseconds=0, year=None, month=None, day=None,
weekday=None, yearday=None, nlyearday=None, hour=None, minute=None,
second=None, microsecond=None)

con el que puedes hacer cosas como calcular el último viernes de un mes:

In [14]: import datetime as dt

In [15]: import dateutil.relativedelta as relativedelta

In [16]: today = dt.date.today()

In [17]: rd = relativedelta.relativedelta(day = 31, weekday = relativedelta.FR(-1))

In [18]: today+rd
Out[18]: datetime.date(2012, 9, 28)
unutbu
fuente
1
Esta es una respuesta fantástica que dio una nueva perspectiva sobre el uso de un relativo delta para cosas como "último viernes del mes" :) ¡Gracias!
PascalVKooten
10

Una diferencia importante que no se destaca en otras respuestas es la presencia de sustantivos en singular y plural para cada primitiva de diferencia de tiempo. Aunque timedeltasolo ofrece sustantivos en plural (por ejemplo hours, days) para denotar la diferencia de tiempo relativa, también relativedeltaofrece sustantivos en singular (por ejemplo hour, day) para denotar información de tiempo absoluto.

Esto se desprende de la definición de las 2 clases:

Definition:   datetime.timedelta([days[, seconds[, microseconds[, 
milliseconds[, minutes[, hours[, weeks]]]]]]])

Definition:   relativedelta.relativedelta(self, dt1=None, dt2=None,
years=0, months=0, days=0, leapdays=0, weeks=0, hours=0, minutes=0,
seconds=0, microseconds=0, year=None, month=None, day=None,
weekday=None, yearday=None, nlyearday=None, hour=None, minute=None,
second=None, microsecond=None)

Ahora, ¿qué hace exactamente la forma singular? La forma singular crea un delta que cuando se agrega a un datetimeobjeto, establece esa primitiva de fecha / hora específica en el datetimeobjeto a la mencionada en el relativedelta. He aquí un pequeño ejemplo:

>>> import datetime as dt; from dateutil.relativedelta import *
>>> NOW = dt.datetime(2018, 11, 17, 9, 6, 31)
>>> NOW
datetime.datetime(2018, 11, 17, 9, 6, 31)
>>> NOW + relativedelta(hours=1) #Simply add one hour
datetime.datetime(2018, 11, 17, 10, 6, 31)
>>> NOW + relativedelta(hour=1) #Set the hour to 01:00 am
datetime.datetime(2018, 11, 17, 1, 6, 31)

Esto puede llevar a que relativedeltase utilice para algunas aplicaciones interesantes, que pueden ser complicadas de implementar utilizando timedelta. Uno que viene rápidamente a la mente es el redondeo.

Una aplicación interesante: redondeo rápido

Ahora le mostraré cómo relativedeltaes más expresivo al redondear un datetimeobjeto al minuto, hora, día, etc.

Redondeando a la hora más cercana:

Observe lo sencillo que es redondear usando relativedelta:

#Using `relativedelta`
NOW + relativedelta(hours=1, minute=0, second=0, microsecond=0)

#Using `timedelta`
dt.combine(NOW.date(),dt.time(NOW.hour,0,0)) + dt.timedelta(0,60*60,0)

Otros redondeos más complicados se pueden lograr fácilmente utilizando relativedelta. Sin embargo, tenga en cuenta que todos los redondeos que puede realizar relativedeltatambién se pueden realizar mediante datetimefunciones y timedelta, solo de una manera un poco más complicada.

shivams
fuente