260 votes

Comment incrémenter la date et l'heure de x mois personnalisés en python sans utiliser de bibliothèque

J'ai besoin d'incrémenter le mois d'une valeur datetime

next_month = datetime.datetime(mydate.year, mydate.month+1, 1)

quand le mois est 12, il devient 13 et déclenche une erreur "month must be in 1..12". (Je m'attendais à ce que l'année soit incrémentée)

Je voulais utiliser timedelta, mais il ne prend pas l'argument du mois. Il y a le package python relativedelta, mais je ne veux pas l'installer juste pour ça. Il y a aussi une solution en utilisant strtotime.

time = strtotime(str(mydate));
next_month = date("Y-m-d", strtotime("+1 month", time));

Je ne veux pas convertir de datetime en str puis en time, puis en datetime; c'est donc toujours une bibliothèque aussi

Est-ce que quelqu'un a une bonne et simple solution comme utiliser timedelta?

4 votes

Il s'agit d'une lacune de la balise datetime de Python qui doit être capable de faire datetime.timedelta(months=6) . La méthode LocalDate.plusMonths() de Java incrémente le mois, puis assure une date valide en décrémentant le champ jour à la dernière date valide du mois. Python devrait faire la même chose par défaut sans avoir recours à des modules externes, mais tant que ce n'est pas corrigé, le code java peut être facilement porté - en fait, c'est à peu près le même que le code dans la réponse acceptée.

570voto

Atul Arvind Points 4264

Ceci est une méthode courte et simple pour ajouter un mois à une date en utilisant le relativedelta de dateutil.

from datetime import datetime
from dateutil.relativedelta import relativedelta

date_after_month = datetime.today()+ relativedelta(months=1)
print('Aujourd'hui : ',datetime.today().strftime('%d/%m/%Y'))
print('Après un mois :', date_after_month.strftime('%d/%m/%Y'))

Aujourd'hui : 01/03/2013

Après un mois : 01/04/2013

Un mot d'avertissement : relativedelta(months=1) et relativedelta(month=1) ont des significations différentes. Passer month=1 remplacera le mois dans la date d'origine par janvier, tandis que passer months=1 ajoutera un mois à la date d'origine.

Remarque : cela nécessitera le module python-dateutil. Si vous êtes sur Linux, vous devez exécuter cette commande dans le terminal pour l'installer.

sudo apt-get update && sudo pip install python-dateutil

Explication : Ajouter une valeur de mois en python

43 votes

Cela nécessite le module python-dateutil, cependant.

1 votes

Vous pouvez aussi utiliser pip install --user python-dateutil si vous ne pouvez pas installer le package globalement (ou si vous souhaitez une version différente).

1 votes

Quelle est la différence entre timedelta et relativedelta dans le package dateutil ?

177voto

Dave Webb Points 90034

Modifier - basé sur votre commentaire selon lequel les dates doivent être arrondies vers le bas s'il y a moins de jours dans le mois suivant, voici une solution :

import datetime
import calendar

def add_months(sourcedate, mois):
    mois = sourcedate.month - 1 + mois
    annee = sourcedate.year + mois // 12
    mois = mois % 12 + 1
    jour = min(sourcedate.day, calendar.monthrange(annee,mois)[1])
    return datetime.date(annee, mois, jour)

En utilisation :

>>> somedate = datetime.date.today()
>>> somedate
datetime.date(2010, 11, 9)
>>> add_months(somedate,1)
datetime.date(2010, 12, 9)
>>> add_months(somedate,23)
datetime.date(2012, 10, 9)
>>> otherdate = datetime.date(2010,10,31)
>>> add_months(otherdate,1)
datetime.date(2010, 11, 30)

Aussi, si vous ne vous souciez pas des heures, des minutes et des secondes, vous pourriez utiliser date plutôt que datetime. Si vous vous souciez des heures, minutes et secondes, vous devez modifier mon code pour utiliser datetime et copier les heures, minutes et secondes de la source vers le résultat.

2 votes

Si c'était le 31 octobre, alors ce serait le 30 novembre

1 votes

Mais je pense que le mois risque de déborder ici --> mois = (sourcedate.month - 1 + mois) % 12 + 1. Ne pensez-vous pas qu'il est préférable de résoudre l'année après avoir calculé le mois ?

0 votes

Pas sûr de comprendre votre commentaire. Le modulo empêche le mois de déborder et dans le code, il n'importe pas dans quel ordre l'année et le mois sont calculés.

45voto

Cyril N. Points 7683

Voici mon sel :

current = datetime.datetime(mydate.year, mydate.month, 1)
next_month = datetime.datetime(mydate.year + int(mydate.month / 12), ((mydate.month % 12) + 1), 1)

Rapide et facile :)

2 votes

Cela ne résout pas le problème : cela vous emmène au premier jour du mois suivant, pas au 'même jour'. Bien sûr, vous pourriez changer le "1" en mydate.day, mais alors vous risquez une erreur lorsque vous passez par exemple du 31 janvier à février.

7 votes

Cela ne résout pas entièrement le problème de l'OP, mais cela fonctionne pour mon cas.

0 votes

next_month = datetime(year+1 if month == 12 else year, 1 if month == 12 else month)

18voto

jargalan Points 1127

Puisque personne n'a proposé de solution, voici comment j'ai résolu jusqu'à présent

année, mois = divmod(madate.month+1, 12)
if mois == 0: 
      mois = 12
      année = année -1
mois_suivant = datetime.datetime(madate.year + année, mois, 1)

0 votes

Joli, à peu près la même chose avec moins de code. c'est une victoire.

3 votes

Bien que cela ne résolve pas le problème : cela vous emmène au premier jour du mois suivant, pas le 'même jour'.

0 votes

@MatthewSchinckel Vous pourriez simplement remplacer le 1 à la fin par le jour actuel, mais alors vous devriez vérifier les jours 31/30 (sans parler de février)

13voto

Eric Clack Points 568

Utilisez le package monthdelta, il fonctionne exactement comme timedelta mais pour les mois calendaires plutôt que pour les jours/heures/etc.

Voici un exemple :

from monthdelta import MonthDelta

def prev_month(date):
    """Reculer d'un mois et préserver le jour si possible"""
    return date + MonthDelta(-1)

Comparez cela avec l'approche DIY :

def prev_month(date):
    """Reculer d'un mois et préserver le jour si possible"""
    jour_du_mois = date.day
    if jour_du_mois != 1:
           date = date.replace(day=1)
    date -= datetime.timedelta(days=1)
    while True:
           try:
                   date = date.replace(day=jour_du_mois)
                   return date
           except ValueError:
                   jour_du_mois -= 1

1 votes

Ceci est la solution la plus simple.

3 votes

Si je dois installer un package différent, je préfère prendre python-dateutil

0 votes

J'avais besoin d'utiliser monthdelta.monthdelta(-1).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X