Antworten:
Ich habe dies früher nicht bemerkt, als ich mir die Dokumentation für das calendar
Modul angesehen habe , aber eine Methode namens ruft monthrange
diese Informationen auf:
monthrange (Jahr, Monat)
Gibt den Wochentag des ersten Tages des Monats und die Anzahl der Tage im Monat für das angegebene Jahr und den angegebenen Monat zurück.
>>> import calendar
>>> calendar.monthrange(2002,1)
(1, 31)
>>> calendar.monthrange(2008,2)
(4, 29)
>>> calendar.monthrange(2100,2)
(0, 28)
damit:
calendar.monthrange(year, month)[1]
scheint der einfachste Weg zu sein.
Um ganz klar zu sein, monthrange
unterstützt auch Schaltjahre:
>>> from calendar import monthrange
>>> monthrange(2012, 2)
(2, 29)
Meine vorherige Antwort funktioniert immer noch, ist aber eindeutig nicht optimal.
28
als die Antwort, die richtig ist, unter Verwendung der Regeln für den Gregorianischen Kalender
monthrange
sei ein verwirrender Name. Sie würden denken, es würde zurückkehren (first_day, last_day)
, nicht(week_day_of_first_day, number_of_days)
Wenn Sie das calendar
Modul nicht importieren möchten , kann eine einfache zweistufige Funktion auch sein:
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)
Ausgänge:
>>> 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
BEARBEITEN: Eine sauberere Lösung finden Sie in der Antwort von @Blair Conrad
>>> import datetime
>>> datetime.date(2000, 2, 1) - datetime.timedelta(days=1)
datetime.date(2000, 1, 31)
today.month + 1 == 13
und Sie einen bekommen ValueError
.
(today.month % 12) + 1
da 12 % 12
gibt 0
Dies ist eigentlich ziemlich einfach mit dateutil.relativedelta
(Paket Python-Datetutil für Pip). day=31
wird immer immer den letzten Tag des Monats zurückgeben.
Beispiel:
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)
gibt datetime(2014, 3, 4, 0, 0)
...
months
hinzugefügt, dann das seconds
subtrahiert wird. Da sie bestanden werden, **kwargs
würde ich mich nicht darauf verlassen und eine Reihe von getrennten Operationen durchführen: now + relative(months=+1) + relative(day=1) + relative(days=-1)
was eindeutig ist.
last_day = (<datetime_object> + relativedelta(day=31)).day
EDIT: siehe meine andere Antwort . Es hat eine bessere Implementierung als diese, die ich hier lasse, nur für den Fall, dass jemand daran interessiert ist, wie man seinen eigenen Taschenrechner "rollen" kann.
@ John Millikin gibt eine gute Antwort mit der zusätzlichen Schwierigkeit, den ersten Tag des nächsten Monats zu berechnen.
Folgendes ist nicht besonders elegant, aber um den letzten Tag des Monats herauszufinden, in dem ein bestimmtes Datum lebt, können Sie versuchen:
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)
. Sie sollten vermeiden, datetime.now zweimal anzurufen, falls Sie es am 31. Dezember kurz vor Mitternacht und dann kurz nach Mitternacht angerufen haben. Sie erhalten den 01.01.2016 anstelle des 01.12.2016 oder des 01.01.2017.
date
ist eine Instanz datetime.date
, datetime.datetime
und auch pandas.Timestamp
.
Wenn dateutil.relativedelta
Sie verwenden, erhalten Sie das letzte Datum des Monats wie folgt:
from dateutil.relativedelta import relativedelta
last_date_of_month = datetime(mydate.year, mydate.month, 1) + relativedelta(months=1, days=-1)
Die Idee ist, den ersten Tag des Monats zu erhalten und relativedelta
1 Monat voraus und 1 Tag zurück zu gehen, damit Sie den letzten Tag des gewünschten Monats erhalten.
Eine andere Lösung wäre, so etwas zu tun:
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
Und nutzen Sie die Funktion wie folgt:
>>>
>>> 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)
Wenn Sie bereit sind, eine externe Bibliothek zu verwenden, besuchen Sie http://crsmithdev.com/arrow/
Sie können dann den letzten Tag des Monats erhalten mit:
import arrow
arrow.utcnow().ceil('month').date()
Dies gibt ein Datumsobjekt zurück, das Sie dann bearbeiten können.
Um das letzte Datum des Monats zu erhalten, machen wir ungefähr so:
from datetime import date, timedelta
import calendar
last_day = date.today().replace(day=calendar.monthrange(date.today().year, date.today().month)[1])
Um zu erklären, was wir hier tun, werden wir es in zwei Teile aufteilen:
Zunächst wird die Anzahl der Tage des aktuellen Monats ermittelt, für die wir monthrange verwenden. Blair Conrad hat seine Lösung bereits erwähnt:
calendar.monthrange(date.today().year, date.today().month)[1]
zweite ist immer das letzte Datum selbst , die wir mit Hilfe tun ersetzen zB
>>> date.today()
datetime.date(2017, 1, 3)
>>> date.today().replace(day=31)
datetime.date(2017, 1, 31)
und wenn wir sie wie oben erwähnt kombinieren, erhalten wir eine dynamische Lösung.
date.replace(day=day)
damit jeder weiß, was los ist.
In Python 3.7 gibt es die undokumentierte calendar.monthlen(year, month)
Funktion :
>>> calendar.monthlen(2002, 1)
31
>>> calendar.monthlen(2008, 2)
29
>>> calendar.monthlen(2100, 2)
28
Dies entspricht dem dokumentierten calendar.monthrange(year, month)[1]
Anruf .
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)
Benutze 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)
Für mich ist es der einfachste Weg:
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)
Der einfachste Weg (ohne Kalender importieren zu müssen) besteht darin, den ersten Tag des nächsten Monats abzurufen und dann einen Tag davon abzuziehen.
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
Ausgabe:
datetime.datetime(2017, 11, 30, 0, 0)
PS: Dieser Code läuft im Vergleich zum import calendar
Ansatz schneller . siehe unten:
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)
AUSGABE:
Time Spent= 0:00:00.097814
Time Spent= 0:00:00.109791
In diesem Code wird davon ausgegangen, dass Sie das Datum des letzten Tages des Monats möchten (dh nicht nur den TT-Teil, sondern das gesamte JJJJMMTT-Datum).
import calendar
?
Hier ist eine andere Antwort. Keine zusätzlichen Pakete erforderlich.
datetime.date(year + int(month/12), month%12+1, 1)-datetime.timedelta(days=1)
Holen Sie sich den ersten Tag des nächsten Monats und subtrahieren Sie einen Tag davon.
Sie können das Enddatum selbst berechnen. Die einfache Logik besteht darin, einen Tag vom Startdatum des nächsten Monats zu subtrahieren. :) :)
Schreiben Sie also eine benutzerdefinierte Methode.
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
Berufung,
end_date_of_a_month(datetime.datetime.now().date())
Das Enddatum dieses Monats wird zurückgegeben. Übergeben Sie ein beliebiges Datum an diese Funktion. gibt Ihnen das Enddatum dieses Monats zurück.
Sie können relativedelta
https://dateutil.readthedocs.io/en/stable/relativedelta.html verwenden
month_end = <your datetime value within the month> + relativedelta(day=31)
, um den letzten Tag zu erhalten.
Dies ist für mich die einfachste Lösung, wenn ich nur die Standard-Datetime-Bibliothek verwende:
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)
Dies spricht nicht die Hauptfrage an, aber ein netter Trick, um den letzten Wochentag in einem Monat zu erhalten, ist die Verwendung calendar.monthcalendar
, die eine Datumsmatrix zurückgibt, die mit Montag als erster Spalte bis Sonntag als letzter Spalte organisiert ist.
# 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
Das Ganze [0:-2]
Ganze ist, die Wochenendsäulen zu rasieren und wegzuwerfen. Daten, die außerhalb des Monats liegen, werden mit 0 angezeigt, sodass das Maximum sie effektiv ignoriert.
Die Verwendung von numpy.ravel
ist nicht unbedingt erforderlich, aber ich hasse es, mich auf die bloße Konvention zu verlassen , numpy.ndarray.max
die das Array abflacht, wenn nicht angegeben wird, über welche Achse berechnet werden soll.
import calendar
from time import gmtime, strftime
calendar.monthrange(int(strftime("%Y", gmtime())), int(strftime("%m", gmtime())))[1]
Ausgabe:
31
Dies gibt den letzten Tag des aktuellen Monats aus. In diesem Beispiel war es der 15. Mai 2016. Ihre Ausgabe kann also unterschiedlich sein, die Ausgabe beträgt jedoch so viele Tage wie der aktuelle Monat. Großartig, wenn Sie den letzten Tag des Monats überprüfen möchten, indem Sie einen täglichen Cron-Job ausführen.
Damit:
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
Ausgabe:
False
Es sei denn, es ist der letzte Tag des Monats.
Wenn Sie Ihre eigene kleine Funktion erstellen möchten, ist dies ein guter Ausgangspunkt:
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
Dazu muss man die Regeln für die Schaltjahre kennen:
Im folgenden Code gibt 'get_last_day_of_month (dt)' dies mit einem Datum im Zeichenfolgenformat wie 'JJJJ-MM-TT' an.
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 )
Am einfachsten ist es, datetime
eine Datumsberechnung zu verwenden, z. B. einen Tag vom ersten Tag des nächsten Monats abzuziehen:
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)
)
Alternativ können Sie calendar.monthrange()
die Anzahl der Tage in einem Monat ermitteln (unter Berücksichtigung der Schaltjahre) und das Datum entsprechend aktualisieren:
import calendar, datetime
def last_day_of_month(d: datetime.date) -> datetime.date:
return d.replace(day=calendar.monthrange(d.year, d.month)[1])
Ein schneller Benchmark zeigt, dass die erste Version spürbar schneller ist:
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)
Hier ist eine lange (leicht verständliche) Version, die sich jedoch um Schaltjahre kümmert.
Prost, 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
und auch if year % 400 == 0: leap_year_flag = 1
mit geringfügigen Änderungen loswerden
Hier ist eine lösungsbasierte Python Lambdas:
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)
Das next_month
Lambda findet die Tupeldarstellung des ersten Tages des nächsten Monats und wechselt zum nächsten Jahr. Das month_end
Lambda wandelt ein Datum ( dte
) in ein Tupel um, wendet es an next_month
und erstellt ein neues Datum. Dann ist das "Monatsende" nur der erste Tag des nächsten Monats minus timedelta(days=1)
.