A ma connaissance, en Python, à l'aide de la méthode timedelta du module datetime, il est très facile d'ajouter ou de retrancher des jours à une date mais quand il s'agit de le faire avec des mois, les choses se compliquent.
En effet tous les mois n'ayant pas le même nombre de jours, il devient incertain d'utiliser cette méthode.
Le module dateutil.relativedelta permet d'ajouter ou de retrancher n'importe quelle unité de temps à une date ou de calculer l'écart entre 2 dates.
Voici quelques exemples
>>> from dateutil.relativedelta import relativedelta
>>> from datetime import datetime
>>> dt1 = datetime(2025,1,26)
>>> dt2 = datetime(2024,11,7)
>>> relativedelta(dt1, dt2) # Ecart entre deux dates
relativedelta(months=+2, days=+19)
>>> dt1 = datetime(2025,1,26,18,23)
>>> dt2 = datetime(2024,11,7,4,35)
>>> relativedelta(dt1, dt2) # Idem mais en ajoutant les heures et les minutes
relativedelta(months=+2, days=+19, hours=+13, minutes=+48)
>>> dt1 = datetime.now()
>>> dt1
datetime.datetime(2025, 1, 26, 18, 24, 14, 103624)
>>> dt1 + relativedelta(months=26) # On ajoute 26 mois
datetime.datetime(2027, 3, 26, 18, 24, 14, 103624)
>>> dt1 + relativedelta(days=55) # On ajoute 55 jours
datetime.datetime(2025, 3, 22, 18, 24, 14, 103624)
>>> dt1 + relativedelta(days=-55) # On retranche 55 jours
datetime.datetime(2024, 12, 2, 18, 24, 14, 103624)
>>> dt1 - relativedelta(days=55) # Idem
datetime.datetime(2024, 12, 2, 18, 24, 14, 103624)
>>> dt1 + relativedelta(seconds=56894) # On ajoute 56894 secondes
datetime.datetime(2025, 1, 27, 10, 12, 28, 103624)m
>>> dt1 + relativedelta(weeks=99) # On ajoute 99 semaines
datetime.datetime(2026, 12, 20, 18, 24, 14, 103624)
>>> dt1 + relativedelta(month=3) # On change le mois
datetime.datetime(2025, 3, 26, 18, 24, 14, 103624)
>>> from dateutil.relativedelta import MO, TU, WE, TH, FR, SA, SU
>>> dt1 + relativedelta(weekday=WE(1)) # Premier mercredi suivant
datetime.datetime(2025, 1, 29, 18, 24, 14, 103624)
>>> dt1 + relativedelta(weekday=WE(-1)) # Premier mercredi d'avant
datetime.datetime(2025, 1, 22, 18, 24, 14, 103624)
Sinon, je me suis amusé à développer cette fonction getNMonthsLessOrMore qui utilise à la fois le module datetime et le module calendar pour arriver au résultat souhaité.
from datetime import datetime
import calendar
def getNMonthsLessOrMore(startDate : datetime, nbMonths : int) -> list:
class DateTimeFormat(Exception):
pass
class NbMonthsFormat(Exception):
pass
def getDayOfMonth(year, month, day):
tmpCal = list(calendar.Calendar().itermonthdays(year, month))
for x in range(day, 0, -1):
if x in tmpCal: return x
return 1
try:
if not isinstance(startDate, datetime): raise DateTimeFormat()
if not isinstance(nbMonths, int): raise NbMonthsFormat()
except DateTimeFormat:
return False, "La date de départ doit être au format datetime.datetime"
except NbMonthsFormat:
return False, "Le nombre de mois doit être un entier positif ou négatif"
else:
if nbMonths == 0: return [startDate]
L = []
tmpDate = datetime(startDate.year, startDate.month, 1)
if nbMonths < 0:
for i in range(0, nbMonths, -1):
y, m = calendar.prevmonth(tmpDate.year, tmpDate.month)
tmpDate = datetime(y, m, getDayOfMonth(y, m, startDate.day))
L.append(tmpDate)
else:
for i in range(0, nbMonths, 1):
y, m = calendar.nextmonth(tmpDate.year, tmpDate.month)
tmpDate = datetime(y, m, getDayOfMonth(y, m, startDate.day))
L.append(tmpDate)
return L
Exécution de la fonction:
>>> getNMonthsLessOrMore(datetime.now(), -6)
[datetime.datetime(2019, 12, 23, 0, 0), datetime.datetime(2019, 11, 23, 0, 0), datetime.datetime(2019, 10, 23, 0, 0), datetime.datetime(2019, 9, 23, 0, 0), datetime.datetime(2019, 8, 23, 0, 0), datetime.datetime(2019, 7, 23, 0, 0)]
>>> getNMonthsLessOrMore(datetime.now(), 8)
[datetime.datetime(2020, 2, 23, 0, 0), datetime.datetime(2020, 3, 23, 0, 0), datetime.datetime(2020, 4, 23, 0, 0), datetime.datetime(2020, 5, 23, 0, 0), datetime.datetime(2020, 6, 23, 0, 0), datetime.datetime(2020, 7, 23, 0, 0), datetime.datetime(2020, 8, 23, 0, 0), datetime.datetime(2020, 9, 23, 0, 0)]
>>> getNMonthsLessOrMore(datetime.now(), 0)
[datetime.datetime(2020, 1, 23, 7, 31, 43, 913244)]