Réponses:
Je ne l'avais pas remarqué plus tôt lorsque je regardais la documentation du calendar
module , mais une méthode appelée monthrange
fournit ces informations:
monthrange (année, mois)
Renvoie le jour de la semaine du premier jour du mois et le nombre de jours du mois, pour l'année et le mois spécifiés.
>>> import calendar
>>> calendar.monthrange(2002,1)
(1, 31)
>>> calendar.monthrange(2008,2)
(4, 29)
>>> calendar.monthrange(2100,2)
(0, 28)
donc:
calendar.monthrange(year, month)[1]
semble être la façon la plus simple de procéder.
Pour être clair, monthrange
prend également en charge les années bissextiles:
>>> from calendar import monthrange
>>> monthrange(2012, 2)
(2, 29)
Ma réponse précédente fonctionne toujours, mais est clairement sous-optimale.
28
comme la réponse, qui est correcte, en utilisant les règles du calendrier grégorien
monthrange
c'est un nom déroutant. On pourrait penser qu'il reviendrait (first_day, last_day)
, pas(week_day_of_first_day, number_of_days)
Si vous ne souhaitez pas importer le calendar
module, une simple fonction en deux étapes peut également être:
import datetime
def last_day_of_month(any_day):
next_month = any_day.replace(day=28) + datetime.timedelta(days=4) # this will never fail
return next_month - datetime.timedelta(days=next_month.day)
Les sorties:
>>> for month in range(1, 13):
... print last_day_of_month(datetime.date(2012, month, 1))
...
2012-01-31
2012-02-29
2012-03-31
2012-04-30
2012-05-31
2012-06-30
2012-07-31
2012-08-31
2012-09-30
2012-10-31
2012-11-30
2012-12-31
EDIT: Voir la réponse de @Blair Conrad pour une solution plus propre
>>> import datetime
>>> datetime.date(2000, 2, 1) - datetime.timedelta(days=1)
datetime.date(2000, 1, 31)
today.month + 1 == 13
vous obtenez un ValueError
.
(today.month % 12) + 1
puisque 12 % 12
donne 0
C'est en fait assez simple avec dateutil.relativedelta
(paquet python-datetutil pour pip). day=31
retournera toujours toujours le dernier jour du mois.
Exemple:
from datetime import datetime
from dateutil.relativedelta import relativedelta
date_in_feb = datetime.datetime(2013, 2, 21)
print datetime.datetime(2013, 2, 21) + relativedelta(day=31) # End-of-month
>>> datetime.datetime(2013, 2, 28, 0, 0)
datetime(2014, 2, 1) + relativedelta(days=31)
donne datetime(2014, 3, 4, 0, 0)
...
months
soit ajouté, puis le seconds
soustrait. Puisqu'ils sont passés, **kwargs
je ne m'appuierais pas sur cela et je ferais une série d'opérations distinctes: now + relative(months=+1) + relative(day=1) + relative(days=-1)
ce qui est sans ambiguïté.
last_day = (<datetime_object> + relativedelta(day=31)).day
EDIT: voir mon autre réponse . Il a une meilleure implémentation que celle-ci, que je laisse ici juste au cas où quelqu'un serait intéressé à voir comment on pourrait "rouler sa propre calculatrice".
@John Millikin donne une bonne réponse, avec la complication supplémentaire du calcul du premier jour du mois suivant.
Ce qui suit n'est pas particulièrement élégant, mais pour comprendre le dernier jour du mois dans lequel se trouve une date donnée, vous pouvez essayer:
def last_day_of_month(date):
if date.month == 12:
return date.replace(day=31)
return date.replace(month=date.month+1, day=1) - datetime.timedelta(days=1)
>>> last_day_of_month(datetime.date(2002, 1, 17))
datetime.date(2002, 1, 31)
>>> last_day_of_month(datetime.date(2002, 12, 9))
datetime.date(2002, 12, 31)
>>> last_day_of_month(datetime.date(2008, 2, 14))
datetime.date(2008, 2, 29)
today = datetime.date.today(); start_date = today.replace(day=1)
. Vous voudriez éviter d'appeler datetime.now deux fois, au cas où vous l'auriez appelé juste avant minuit le 31 décembre, puis juste après minuit. Vous obtiendrez 2016-01-01 au lieu de 2016-12-01 ou 2017-01-01.
date
est une instance de datetime.date
, datetime.datetime
et aussi pandas.Timestamp
.
En utilisant dateutil.relativedelta
vous obtiendrez la dernière date du mois comme ceci:
from dateutil.relativedelta import relativedelta
last_date_of_month = datetime(mydate.year, mydate.month, 1) + relativedelta(months=1, days=-1)
L'idée est d'obtenir le premier jour du mois et d'utiliser relativedelta
pour avancer d'un mois et un jour en arrière afin d'obtenir le dernier jour du mois souhaité.
Une autre solution serait de faire quelque chose comme ceci:
from datetime import datetime
def last_day_of_month(year, month):
""" Work out the last day of the month """
last_days = [31, 30, 29, 28, 27]
for i in last_days:
try:
end = datetime(year, month, i)
except ValueError:
continue
else:
return end.date()
return None
Et utilisez la fonction comme ceci:
>>>
>>> last_day_of_month(2008, 2)
datetime.date(2008, 2, 29)
>>> last_day_of_month(2009, 2)
datetime.date(2009, 2, 28)
>>> last_day_of_month(2008, 11)
datetime.date(2008, 11, 30)
>>> last_day_of_month(2008, 12)
datetime.date(2008, 12, 31)
from datetime import timedelta
(any_day.replace(day=1) + timedelta(days=32)).replace(day=1) - timedelta(days=1)
si vous souhaitez utiliser une bibliothèque externe, consultez http://crsmithdev.com/arrow/
Vous pouvez alors obtenir le dernier jour du mois avec:
import arrow
arrow.utcnow().ceil('month').date()
Cela renvoie un objet date que vous pouvez ensuite faire votre manipulation.
Pour obtenir la dernière date du mois, nous faisons quelque chose comme ceci:
from datetime import date, timedelta
import calendar
last_day = date.today().replace(day=calendar.monthrange(date.today().year, date.today().month)[1])
Maintenant, pour expliquer ce que nous faisons ici, nous allons le diviser en deux parties:
le premier est le nombre de jours du mois en cours pour lesquels nous utilisons la plage mensuelle dont Blair Conrad a déjà mentionné sa solution:
calendar.monthrange(date.today().year, date.today().month)[1]
deuxième obtient la dernière date elle-même que nous faisons avec l'aide de remplacer par exemple
>>> date.today()
datetime.date(2017, 1, 3)
>>> date.today().replace(day=31)
datetime.date(2017, 1, 31)
et lorsque nous les combinons comme mentionné en haut, nous obtenons une solution dynamique.
date.replace(day=day)
afin que tout le monde sache ce qui se passe.
Dans Python 3.7, il y a la calendar.monthlen(year, month)
fonction non documentée :
>>> calendar.monthlen(2002, 1)
31
>>> calendar.monthlen(2008, 2)
29
>>> calendar.monthlen(2100, 2)
28
Il est équivalent à l' calendar.monthrange(year, month)[1]
appel documenté .
import datetime
now = datetime.datetime.now()
start_month = datetime.datetime(now.year, now.month, 1)
date_on_next_month = start_month + datetime.timedelta(35)
start_next_month = datetime.datetime(date_on_next_month.year, date_on_next_month.month, 1)
last_day_month = start_next_month - datetime.timedelta(1)
Utilisez des pandas!
def isMonthEnd(date):
return date + pd.offsets.MonthEnd(0) == date
isMonthEnd(datetime(1999, 12, 31))
True
isMonthEnd(pd.Timestamp('1999-12-31'))
True
isMonthEnd(pd.Timestamp(1965, 1, 10))
False
now=datetime.datetime.now(); pd_now = pd.to_datetime(now); print(pd_now.days_in_month)
Pour moi, c'est le moyen le plus simple:
selected_date = date(some_year, some_month, some_day)
if selected_date.month == 12: # December
last_day_selected_month = date(selected_date.year, selected_date.month, 31)
else:
last_day_selected_month = date(selected_date.year, selected_date.month + 1, 1) - timedelta(days=1)
Le moyen le plus simple (sans avoir à importer le calendrier) est d'obtenir le premier jour du mois suivant, puis d'en soustraire un jour.
import datetime as dt
from dateutil.relativedelta import relativedelta
thisDate = dt.datetime(2017, 11, 17)
last_day_of_the_month = dt.datetime(thisDate.year, (thisDate + relativedelta(months=1)).month, 1) - dt.timedelta(days=1)
print last_day_of_the_month
Production:
datetime.datetime(2017, 11, 30, 0, 0)
PS: ce code s'exécute plus rapidement par rapport à l' import calendar
approche; voir ci-dessous:
import datetime as dt
import calendar
from dateutil.relativedelta import relativedelta
someDates = [dt.datetime.today() - dt.timedelta(days=x) for x in range(0, 10000)]
start1 = dt.datetime.now()
for thisDate in someDates:
lastDay = dt.datetime(thisDate.year, (thisDate + relativedelta(months=1)).month, 1) - dt.timedelta(days=1)
print ('Time Spent= ', dt.datetime.now() - start1)
start2 = dt.datetime.now()
for thisDate in someDates:
lastDay = dt.datetime(thisDate.year,
thisDate.month,
calendar.monthrange(thisDate.year, thisDate.month)[1])
print ('Time Spent= ', dt.datetime.now() - start2)
PRODUCTION:
Time Spent= 0:00:00.097814
Time Spent= 0:00:00.109791
Ce code suppose que vous voulez la date du dernier jour du mois (c'est-à-dire, pas seulement la partie DD, mais la date YYYYMMDD entière)
import calendar
?
Voici une autre réponse. Aucun forfait supplémentaire requis.
datetime.date(year + int(month/12), month%12+1, 1)-datetime.timedelta(days=1)
Obtenez le premier jour du mois suivant et soustrayez-en un jour.
Vous pouvez calculer la date de fin vous-même. la logique simple est de soustraire un jour de la date de début du mois prochain. :)
Alors écrivez une méthode personnalisée,
import datetime
def end_date_of_a_month(date):
start_date_of_this_month = date.replace(day=1)
month = start_date_of_this_month.month
year = start_date_of_this_month.year
if month == 12:
month = 1
year += 1
else:
month += 1
next_month_start_date = start_date_of_this_month.replace(month=month, year=year)
this_month_end_date = next_month_start_date - datetime.timedelta(days=1)
return this_month_end_date
Appel,
end_date_of_a_month(datetime.datetime.now().date())
Il renverra la date de fin de ce mois. Passez n'importe quelle date à cette fonction. vous renvoie la date de fin de ce mois.
vous pouvez utiliser relativedelta
https://dateutil.readthedocs.io/en/stable/relativedelta.html
month_end = <your datetime value within the month> + relativedelta(day=31)
qui vous donnera le dernier jour.
C'est la solution la plus simple pour moi en utilisant uniquement la bibliothèque datetime standard:
import datetime
def get_month_end(dt):
first_of_month = datetime.datetime(dt.year, dt.month, 1)
next_month_date = first_of_month + datetime.timedelta(days=32)
new_dt = datetime.datetime(next_month_date.year, next_month_date.month, 1)
return new_dt - datetime.timedelta(days=1)
Cela ne répond pas à la question principale, mais une bonne astuce pour obtenir le dernier jour de la semaine d'un mois est d'utiliser calendar.monthcalendar
, qui renvoie une matrice de dates, organisée avec lundi comme première colonne et dimanche comme dernière.
# Some random date.
some_date = datetime.date(2012, 5, 23)
# Get last weekday
last_weekday = np.asarray(calendar.monthcalendar(some_date.year, some_date.month))[:,0:-2].ravel().max()
print last_weekday
31
La totalité [0:-2]
est de raser les colonnes du week-end et de les jeter. Les dates qui tombent en dehors du mois sont indiquées par 0, donc le max les ignore effectivement.
L'utilisation de numpy.ravel
n'est pas strictement nécessaire, mais je déteste me fier à la simple convention qui numpy.ndarray.max
aplatira le tableau si on ne lui dit pas sur quel axe effectuer le calcul.
import calendar
from time import gmtime, strftime
calendar.monthrange(int(strftime("%Y", gmtime())), int(strftime("%m", gmtime())))[1]
Production:
31
Cela imprimera le dernier jour du mois en cours. Dans cet exemple, c'était le 15 mai 2016. Votre sortie peut donc être différente, mais la sortie sera autant de jours que le mois en cours. Idéal si vous souhaitez vérifier le dernier jour du mois en exécutant une tâche cron quotidienne.
Donc:
import calendar
from time import gmtime, strftime
lastDay = calendar.monthrange(int(strftime("%Y", gmtime())), int(strftime("%m", gmtime())))[1]
today = strftime("%d", gmtime())
lastDay == today
Production:
False
A moins que ce ne soit le dernier jour du mois.
Si vous voulez créer votre propre petite fonction, c'est un bon point de départ:
def eomday(year, month):
"""returns the number of days in a given month"""
days_per_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
d = days_per_month[month - 1]
if month == 2 and (year % 4 == 0 and year % 100 != 0 or year % 400 == 0):
d = 29
return d
Pour cela, vous devez connaître les règles pour les années bissextiles:
Dans le code ci-dessous, 'get_last_day_of_month (dt)' vous donnera ceci, avec une date au format chaîne comme 'YYYY-MM-DD'.
import datetime
def DateTime( d ):
return datetime.datetime.strptime( d, '%Y-%m-%d').date()
def RelativeDate( start, num_days ):
d = DateTime( start )
return str( d + datetime.timedelta( days = num_days ) )
def get_first_day_of_month( dt ):
return dt[:-2] + '01'
def get_last_day_of_month( dt ):
fd = get_first_day_of_month( dt )
fd_next_month = get_first_day_of_month( RelativeDate( fd, 31 ) )
return RelativeDate( fd_next_month, -1 )
La manière la plus simple consiste à utiliser datetime
des mathématiques de date, par exemple soustraire un jour du premier jour du mois suivant:
import datetime
def last_day_of_month(d: datetime.date) -> datetime.date:
return (
datetime.date(d.year + d.month//12, d.month % 12 + 1, 1) -
datetime.timedelta(days=1)
)
Alternativement, vous pouvez utiliser calendar.monthrange()
pour obtenir le nombre de jours dans un mois (en tenant compte des années bissextiles) et mettre à jour la date en conséquence:
import calendar, datetime
def last_day_of_month(d: datetime.date) -> datetime.date:
return d.replace(day=calendar.monthrange(d.year, d.month)[1])
Un benchmark rapide montre que la première version est sensiblement plus rapide:
In [14]: today = datetime.date.today()
In [15]: %timeit last_day_of_month_dt(today)
918 ns ± 3.54 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [16]: %timeit last_day_of_month_calendar(today)
1.4 µs ± 17.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Voici une version longue (facile à comprendre) mais s'occupe des années bissextiles.
cheers, JK
def last_day_month(year, month):
leap_year_flag = 0
end_dates = {
1: 31,
2: 28,
3: 31,
4: 30,
5: 31,
6: 30,
7: 31,
8: 31,
9: 30,
10: 31,
11: 30,
12: 31
}
# Checking for regular leap year
if year % 4 == 0:
leap_year_flag = 1
else:
leap_year_flag = 0
# Checking for century leap year
if year % 100 == 0:
if year % 400 == 0:
leap_year_flag = 1
else:
leap_year_flag = 0
else:
pass
# return end date of the year-month
if leap_year_flag == 1 and month == 2:
return 29
elif leap_year_flag == 1 and month != 2:
return end_dates[month]
else:
return end_dates[month]
else: pass
et vous pouvez également vous débarrasser if year % 400 == 0: leap_year_flag = 1
de modifications mineures
Voici un lambdas en python basé sur une solution:
next_month = lambda y, m, d: (y, m + 1, 1) if m + 1 < 13 else ( y+1 , 1, 1)
month_end = lambda dte: date( *next_month( *dte.timetuple()[:3] ) ) - timedelta(days=1)
Le next_month
lambda trouve la représentation de tuple du premier jour du mois suivant et passe à l'année suivante. Le month_end
lambda transforme une date ( dte
) en tuple, applique next_month
et crée une nouvelle date. Ensuite, la "fin du mois" n'est que le premier jour moins du mois suivant timedelta(days=1)
.