Odpowiedzi:
Nie zauważyłem tego wcześniej, kiedy przeglądałem dokumentację calendar
modułu , ale metoda o nazwie monthrange
zapewnia następujące informacje:
monthrange (rok, miesiąc)
Zwraca dzień tygodnia pierwszego dnia miesiąca i liczbę dni w miesiącu dla określonego roku i miesiąca.
>>> import calendar
>>> calendar.monthrange(2002,1)
(1, 31)
>>> calendar.monthrange(2008,2)
(4, 29)
>>> calendar.monthrange(2100,2)
(0, 28)
więc:
calendar.monthrange(year, month)[1]
wydaje się najprostszą drogą.
Dla jasności monthrange
obsługuje także lata przestępne:
>>> from calendar import monthrange
>>> monthrange(2012, 2)
(2, 29)
Moja poprzednia odpowiedź wciąż działa, ale jest wyraźnie nieoptymalna.
28
jako odpowiedź, która jest poprawna, przy użyciu reguł kalendarza gregoriańskiego
monthrange
to mylące imię. Można by pomyśleć, że wróci (first_day, last_day)
, a nie(week_day_of_first_day, number_of_days)
Jeśli nie chcesz importować calendar
modułu, prostą funkcją dwuetapową może być również:
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)
Wyjścia:
>>> 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
EDYCJA: Zobacz odpowiedź @Blair Conrad na czystsze rozwiązanie
>>> import datetime
>>> datetime.date(2000, 2, 1) - datetime.timedelta(days=1)
datetime.date(2000, 1, 31)
today.month + 1 == 13
i dostajesz ValueError
.
(today.month % 12) + 1
ponieważ 12 % 12
daje 0
W rzeczywistości jest to dość łatwe dateutil.relativedelta
(pakiet python-datetutil dla pip). day=31
zawsze zawsze zwraca ostatni dzień miesiąca.
Przykład:
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)
daje datetime(2014, 3, 4, 0, 0)
...
months
jest dodawane, a następnie seconds
odejmowane. Ponieważ są one przekazywane, ponieważ **kwargs
nie polegałbym na tym i wykonałbym szereg oddzielnych operacji: now + relative(months=+1) + relative(day=1) + relative(days=-1)
co jest jednoznaczne.
last_day = (<datetime_object> + relativedelta(day=31)).day
EDYCJA: zobacz moją drugą odpowiedź . Ma lepszą implementację niż ta, którą zostawiam tutaj na wypadek, gdyby ktoś chciał zobaczyć, jak można „wyrzucić własny” kalkulator.
@John Millikin daje dobrą odpowiedź, z dodatkową komplikacją obliczania pierwszego dnia następnego miesiąca.
Poniższe informacje nie są szczególnie eleganckie, ale aby dowiedzieć się, jaki jest ostatni dzień miesiąca, w którym przypada data, możesz spróbować:
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)
. Chciałbyś uniknąć dzwonienia do datetime.now dwa razy, na wypadek, gdyby zadzwoniłeś tuż przed północą 31 grudnia, a potem tuż po północy. Dostaniesz 01.01.2016 zamiast 01.12.2016 lub 01.01.2017.
date
są instancją datetime.date
, datetime.datetime
a także pandas.Timestamp
.
Za pomocą dateutil.relativedelta
otrzymasz ostatnią datę miesiąca w ten sposób:
from dateutil.relativedelta import relativedelta
last_date_of_month = datetime(mydate.year, mydate.month, 1) + relativedelta(months=1, days=-1)
Chodzi o to, aby uzyskać pierwszy dzień miesiąca i relativedelta
przejść do następnego miesiąca i 1 dnia wstecz, aby uzyskać ostatni dzień miesiąca, który chciałeś.
Innym rozwiązaniem byłoby zrobienie czegoś takiego:
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
I użyj następującej funkcji:
>>>
>>> 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)
jeśli chcesz skorzystać z zewnętrznej biblioteki, sprawdź http://crsmithdev.com/arrow/
U możesz uzyskać ostatni dzień miesiąca dzięki:
import arrow
arrow.utcnow().ceil('month').date()
Zwraca to obiekt daty, który możesz następnie manipulować.
Aby uzyskać ostatnią datę miesiąca, robimy coś takiego:
from datetime import date, timedelta
import calendar
last_day = date.today().replace(day=calendar.monthrange(date.today().year, date.today().month)[1])
Teraz, aby wyjaśnić, co tu robimy, podzielimy to na dwie części:
po pierwsze, podaje liczbę dni bieżącego miesiąca, dla których używamy przedziału miesiąca, o którym Blair Conrad wspomniał już o swoim rozwiązaniu:
calendar.monthrange(date.today().year, date.today().month)[1]
drugim jest sama data, którą robimy za pomocą zamiany np
>>> date.today()
datetime.date(2017, 1, 3)
>>> date.today().replace(day=31)
datetime.date(2017, 1, 31)
a kiedy je połączymy, jak wspomniano na górze, otrzymujemy dynamiczne rozwiązanie.
date.replace(day=day)
aby wszyscy wiedzieli, co się dzieje.
W Pythonie 3.7 znajduje się nieudokumentowana calendar.monthlen(year, month)
funkcja :
>>> calendar.monthlen(2002, 1)
31
>>> calendar.monthlen(2008, 2)
29
>>> calendar.monthlen(2100, 2)
28
Jest to odpowiednik udokumentowanego calendar.monthrange(year, month)[1]
połączenia .
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)
Używaj pand!
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)
Dla mnie to najprostszy sposób:
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)
Najprostszym sposobem (bez konieczności importowania kalendarza) jest pobranie pierwszego dnia następnego miesiąca, a następnie odjęcie od niego jednego dnia.
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
Wynik:
datetime.datetime(2017, 11, 30, 0, 0)
PS: Ten kod działa szybciej niż import calendar
podejście; patrz poniżej:
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)
WYNIK:
Time Spent= 0:00:00.097814
Time Spent= 0:00:00.109791
Ten kod zakłada, że chcesz mieć datę ostatniego dnia miesiąca (tj. Nie tylko część DD, ale całą datę RRRRMMDD)
import calendar
?
Oto kolejna odpowiedź. Nie są wymagane żadne dodatkowe pakiety.
datetime.date(year + int(month/12), month%12+1, 1)-datetime.timedelta(days=1)
Uzyskaj pierwszy dzień następnego miesiąca i odejmij od niego dzień.
Możesz sam obliczyć datę końcową. prosta logika polega na odjęciu dnia od daty_początkowej następnego miesiąca. :)
Napisz więc niestandardową metodę,
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
Powołanie,
end_date_of_a_month(datetime.datetime.now().date())
Zwróci datę zakończenia tego miesiąca. Podaj dowolną datę do tej funkcji. zwraca datę zakończenia tego miesiąca.
możesz użyć relativedelta
https://dateutil.readthedocs.io/en/stable/relativedelta.html
month_end = <your datetime value within the month> + relativedelta(day=31)
, który da ci ostatni dzień.
To jest dla mnie najprostsze rozwiązanie, używając tylko standardowej biblioteki datetime:
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)
Nie rozwiązuje to głównego pytania, ale jedną fajną sztuczką, aby uzyskać ostatni dzień tygodnia w miesiącu, jest użycie calendar.monthcalendar
, która zwraca macierz dat, zorganizowanych od poniedziałku jako pierwszej kolumny do niedzieli jako ostatniej.
# 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
Chodzi [0:-2]
o to, aby ogolić kolumny weekendowe i wyrzucić je. Daty przypadające poza miesiącem są wskazywane przez 0, więc maksimum skutecznie je ignoruje.
Użycie numpy.ravel
nie jest absolutnie konieczne, ale nienawidzę polegać na samej konwencji , numpy.ndarray.max
która spłaszczy tablicę, jeśli nie powie się, którą oś obliczyć.
import calendar
from time import gmtime, strftime
calendar.monthrange(int(strftime("%Y", gmtime())), int(strftime("%m", gmtime())))[1]
Wynik:
31
Spowoduje to wydrukowanie ostatniego dnia niezależnie od bieżącego miesiąca. W tym przykładzie był to 15 maja 2016 r. Twoje wyniki mogą być inne, ale wynik będzie tyle dni, ile wynosi bieżący miesiąc. Świetnie, jeśli chcesz sprawdzić ostatni dzień miesiąca, uruchamiając codzienną pracę crona.
Więc:
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
Wynik:
False
Chyba że jest to ostatni dzień miesiąca.
Jeśli chcesz stworzyć własną małą funkcję, jest to dobry punkt wyjścia:
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
W tym celu musisz znać zasady dotyczące lat przestępnych:
W poniższym kodzie „get_last_day_of_month (dt)” poda ci to, wraz z datą w formacie ciągu, np. „RRRR-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 )
Najprostszym sposobem jest użycie datetime
pewnej matematyki dat, np. Odjęcie dnia od pierwszego dnia następnego miesiąca:
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)
)
Alternatywnie możesz użyć, calendar.monthrange()
aby uzyskać liczbę dni w miesiącu (biorąc pod uwagę lata przestępne) i odpowiednio zaktualizować datę:
import calendar, datetime
def last_day_of_month(d: datetime.date) -> datetime.date:
return d.replace(day=calendar.monthrange(d.year, d.month)[1])
Szybki test porównawczy pokazuje, że pierwsza wersja jest zauważalnie szybsza:
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)
Oto długa (łatwa do zrozumienia) wersja, która dba o lata przestępne.
na zdrowie, 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
a także możesz się pozbyć if year % 400 == 0: leap_year_flag = 1
z drobnymi modyfikacjami
Oto oparte na rozwiązaniu 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)
next_month
Lambda znajduje reprezentację krotny pierwszego dnia następnego miesiąca i przechodzi na następny rok. month_end
Lambda przekształca datę ( dte
) do krotki, stosuje się next_month
i tworzy nową datę. Zatem „koniec miesiąca” to tylko pierwszy dzień następnego miesiąca minus timedelta(days=1)
.