Jawaban:
Saya tidak memperhatikan ini sebelumnya ketika saya melihat dokumentasi untuk calendar
modul , tetapi metode yang disebut monthrange
memberikan informasi ini:
monthrange (year, month)
Mengembalikan hari kerja di hari pertama bulan itu dan jumlah hari dalam sebulan, untuk tahun dan bulan yang ditentukan.
>>> import calendar
>>> calendar.monthrange(2002,1)
(1, 31)
>>> calendar.monthrange(2008,2)
(4, 29)
>>> calendar.monthrange(2100,2)
(0, 28)
begitu:
calendar.monthrange(year, month)[1]
sepertinya cara termudah untuk pergi.
Supaya jelas, monthrange
mendukung tahun kabisat juga:
>>> from calendar import monthrange
>>> monthrange(2012, 2)
(2, 29)
Jawaban saya sebelumnya masih berfungsi, tetapi jelas suboptimal.
28
sebagai jawaban, yang benar, menggunakan aturan untuk kalender Gregorian
monthrange
adalah nama yang membingungkan. Anda akan berpikir itu akan kembali (first_day, last_day)
, tidak(week_day_of_first_day, number_of_days)
Jika Anda tidak ingin mengimpor calendar
modul, fungsi dua langkah sederhana juga bisa:
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)
Output:
>>> 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: Lihat jawaban @Blair Conrad untuk solusi yang lebih bersih
>>> import datetime
>>> datetime.date(2000, 2, 1) - datetime.timedelta(days=1)
datetime.date(2000, 1, 31)
today.month + 1 == 13
dan Anda mendapatkan ValueError
.
(today.month % 12) + 1
sejak 12 % 12
memberikan 0
Ini sebenarnya cukup mudah dengan dateutil.relativedelta
(paket python-datetutil untuk pip).day=31
akan selalu selalu kembali pada hari terakhir bulan itu.
Contoh:
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)
memberi datetime(2014, 3, 4, 0, 0)
...
months
ditambahkan, kemudian seconds
dikurangi. Karena mereka disahkan karena **kwargs
saya tidak akan bergantung pada itu dan melakukan serangkaian operasi terpisah: now + relative(months=+1) + relative(day=1) + relative(days=-1)
yang tidak ambigu.
last_day = (<datetime_object> + relativedelta(day=31)).day
EDIT: lihat jawaban saya yang lain . Ini memiliki implementasi yang lebih baik daripada yang ini, yang saya tinggalkan di sini kalau-kalau ada seseorang yang tertarik melihat bagaimana seseorang bisa "menggulung Anda sendiri" kalkulator.
@John Millikin memberikan jawaban yang baik, dengan komplikasi tambahan dalam menghitung hari pertama bulan berikutnya.
Berikut ini tidak terlalu elegan, tetapi untuk mencari tahu hari terakhir bulan itu pada tanggal tertentu, Anda dapat mencoba:
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)
. Anda ingin menghindari menelepon datetime. Sekarang dua kali, kalau-kalau Anda menyebutnya sebelum tengah malam pada tanggal 31 dan kemudian setelah tengah malam. Anda akan mendapatkan 2016-01-01 bukannya 2016-12-01 atau 2017-01-01.
date
adalah instance dari datetime.date
, datetime.datetime
dan juga pandas.Timestamp
.
Menggunakan dateutil.relativedelta
Anda akan mendapatkan tanggal terakhir bulan seperti ini:
from dateutil.relativedelta import relativedelta
last_date_of_month = datetime(mydate.year, mydate.month, 1) + relativedelta(months=1, days=-1)
Idenya adalah untuk mendapatkan hari pertama bulan itu dan gunakan relativedelta
untuk pergi 1 bulan ke depan dan 1 hari kembali sehingga Anda akan mendapatkan hari terakhir bulan yang Anda inginkan.
Solusi lain adalah melakukan sesuatu seperti ini:
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
Dan gunakan fungsi seperti ini:
>>>
>>> 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)
jika Anda bersedia menggunakan perpustakaan eksternal, lihat http://crsmithdev.com/arrow/
Anda dapat memperoleh hari terakhir bulan itu dengan:
import arrow
arrow.utcnow().ceil('month').date()
Ini mengembalikan objek tanggal yang kemudian dapat Anda lakukan manipulasi Anda.
Untuk mendapatkan tanggal terakhir bulan ini kami melakukan sesuatu seperti ini:
from datetime import date, timedelta
import calendar
last_day = date.today().replace(day=calendar.monthrange(date.today().year, date.today().month)[1])
Sekarang untuk menjelaskan apa yang kita lakukan di sini kita akan memecahnya menjadi dua bagian:
pertama adalah mendapatkan jumlah hari dalam bulan ini yang kami gunakan untuk mengatur rentang bulan yang sudah disebutkan oleh Blair Conrad solusinya:
calendar.monthrange(date.today().year, date.today().month)[1]
kedua adalah mendapatkan tanggal terakhir itu sendiri yang kami lakukan dengan bantuan ganti mis
>>> date.today()
datetime.date(2017, 1, 3)
>>> date.today().replace(day=31)
datetime.date(2017, 1, 31)
dan ketika kita menggabungkannya seperti yang disebutkan di atas kita mendapatkan solusi yang dinamis.
date.replace(day=day)
sehingga semua orang tahu apa yang terjadi.
Di Python 3.7 ada fungsi tidak berdokumencalendar.monthlen(year, month)
:
>>> calendar.monthlen(2002, 1)
31
>>> calendar.monthlen(2008, 2)
29
>>> calendar.monthlen(2100, 2)
28
Ini setara dengan panggilan yang didokumentasikancalendar.monthrange(year, month)[1]
.
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)
Gunakan panda!
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)
Bagi saya itu cara paling sederhana:
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)
Cara termudah (tanpa harus mengimpor kalender), adalah untuk mendapatkan hari pertama bulan berikutnya, dan kemudian kurangi satu hari darinya.
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
Keluaran:
datetime.datetime(2017, 11, 30, 0, 0)
PS: Kode ini berjalan lebih cepat dibandingkan dengan import calendar
pendekatan; Lihat di bawah:
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)
KELUARAN:
Time Spent= 0:00:00.097814
Time Spent= 0:00:00.109791
Kode ini mengasumsikan bahwa Anda menginginkan tanggal hari terakhir bulan itu (yaitu, bukan hanya bagian DD, tetapi seluruh tanggal YYYYMMDD)
import calendar
?
Ini jawaban lain. Tidak diperlukan paket tambahan.
datetime.date(year + int(month/12), month%12+1, 1)-datetime.timedelta(days=1)
Dapatkan hari pertama bulan berikutnya dan kurangi satu hari darinya.
Anda dapat menghitung sendiri tanggal akhirnya. Logikanya sederhana adalah mengurangi satu hari dari tanggal mulai bulan depan. :)
Jadi, tulis metode khusus,
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
Panggilan,
end_date_of_a_month(datetime.datetime.now().date())
Ini akan mengembalikan tanggal akhir bulan ini. Berikan tanggal apa pun ke fungsi ini. mengembalikan tanggal akhir bulan itu kepada Anda.
Anda dapat menggunakan relativedelta
https://dateutil.readthedocs.io/en/stable/relativedelta.html
month_end = <your datetime value within the month> + relativedelta(day=31)
yang akan memberi Anda hari terakhir.
Ini adalah solusi paling sederhana bagi saya hanya menggunakan perpustakaan datetime standar:
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)
Ini tidak menjawab pertanyaan utama, tetapi satu trik bagus untuk mendapatkan hari kerja terakhir dalam sebulan adalah menggunakan calendar.monthcalendar
, yang mengembalikan matriks tanggal, yang diselenggarakan dengan Senin sebagai kolom pertama hingga Minggu sebagai yang terakhir.
# 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
Seluruh [0:-2]
hal yang mencukur kolom akhir pekan dan melemparkan mereka keluar. Tanggal yang jatuh di luar bulan ditandai dengan 0, sehingga maks secara efektif mengabaikannya.
Penggunaan numpy.ravel
tidak sepenuhnya diperlukan, tapi saya benci mengandalkan konvensi belaka yang numpy.ndarray.max
akan meratakan array jika tidak diberi tahu sumbu mana yang harus dihitung.
import calendar
from time import gmtime, strftime
calendar.monthrange(int(strftime("%Y", gmtime())), int(strftime("%m", gmtime())))[1]
Keluaran:
31
Ini akan mencetak hari terakhir dari bulan apa pun saat ini. Dalam contoh ini adalah 15 Mei 2016. Jadi output Anda mungkin berbeda, namun outputnya akan sama dengan hari saat bulan ini. Hebat jika Anda ingin memeriksa hari terakhir bulan itu dengan menjalankan tugas cron harian.
Begitu:
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
Keluaran:
False
Kecuali itu ADALAH hari terakhir bulan itu.
Jika Anda ingin membuat fungsi kecil Anda sendiri, ini adalah titik awal yang baik:
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
Untuk ini, Anda harus tahu aturan untuk tahun kabisat:
Dalam kode di bawah ini 'get_last_day_of_month (dt)' akan memberi Anda ini, dengan tanggal dalam format string seperti '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 )
Cara paling sederhana adalah dengan menggunakan datetime
dan beberapa matematika tanggal, mis. Kurangi satu hari dari hari pertama bulan berikutnya:
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)
)
Atau, Anda dapat menggunakan calendar.monthrange()
untuk mendapatkan jumlah hari dalam sebulan (dengan memperhitungkan tahun kabisat) dan memperbarui tanggal sesuai dengan itu:
import calendar, datetime
def last_day_of_month(d: datetime.date) -> datetime.date:
return d.replace(day=calendar.monthrange(d.year, d.month)[1])
Patokan cepat menunjukkan bahwa versi pertama terasa lebih cepat:
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)
Ini adalah versi yang panjang (mudah dipahami) tetapi menangani tahun kabisat.
bersorak, 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
dan juga Anda dapat menghapus if year % 400 == 0: leap_year_flag = 1
dengan modifikasi kecil
Berikut ini adalah solusi berdasarkan 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)
The next_month
lambda menemukan representasi tuple dari hari pertama bulan berikutnya, dan berguling ke tahun depan. The month_end
lambda mengubah tanggal ( dte
) untuk tupel, berlaku next_month
dan menciptakan tanggal baru. Maka "akhir bulan" hanyalah hari pertama minus bulan depan timedelta(days=1)
.