Câu trả lời:
Tôi đã không nhận thấy điều này sớm hơn khi tôi xem tài liệu cho calendar
mô-đun , nhưng một phương pháp được gọi là monthrange
cung cấp thông tin này:
tháng sắp xếp (năm, tháng)
Trả về ngày trong tuần của ngày đầu tiên của tháng và số ngày trong tháng, cho năm và tháng được chỉ định.
>>> import calendar
>>> calendar.monthrange(2002,1)
(1, 31)
>>> calendar.monthrange(2008,2)
(4, 29)
>>> calendar.monthrange(2100,2)
(0, 28)
vì thế:
calendar.monthrange(year, month)[1]
có vẻ như cách đơn giản nhất để đi
Chỉ cần rõ ràng, monthrange
hỗ trợ năm nhuận là tốt:
>>> from calendar import monthrange
>>> monthrange(2012, 2)
(2, 29)
Câu trả lời trước của tôi vẫn hoạt động, nhưng rõ ràng là tối ưu.
28
như câu trả lời, đúng, sử dụng các quy tắc cho lịch Gregorian
monthrange
là một cái tên khó hiểu. Bạn sẽ nghĩ rằng nó sẽ trở lại (first_day, last_day)
, không phải(week_day_of_first_day, number_of_days)
Nếu bạn không muốn nhập calendar
mô-đun, chức năng hai bước đơn giản cũng có thể là:
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)
Đầu ra:
>>> 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: Xem câu trả lời của @Blair Conrad để biết giải pháp sạch hơn
>>> import datetime
>>> datetime.date(2000, 2, 1) - datetime.timedelta(days=1)
datetime.date(2000, 1, 31)
today.month + 1 == 13
và bạn nhận được một ValueError
.
(today.month % 12) + 1
kể từ khi 12 % 12
cho 0
Điều này thực sự khá dễ dàng với dateutil.relativedelta
(gói python-datetutil cho pip). day=31
sẽ luôn luôn trở lại vào ngày cuối cùng của tháng.
Thí dụ:
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)
cho datetime(2014, 3, 4, 0, 0)
...
months
được thêm vào, sau đó được seconds
trừ đi. Vì chúng được thông qua vì **kwargs
tôi sẽ không dựa vào điều đó và thực hiện một loạt các hoạt động riêng biệt: now + relative(months=+1) + relative(day=1) + relative(days=-1)
không rõ ràng.
last_day = (<datetime_object> + relativedelta(day=31)).day
EDIT: xem câu trả lời khác của tôi . Nó có một triển khai tốt hơn cái này, mà tôi để lại ở đây chỉ trong trường hợp ai đó quan tâm đến việc làm thế nào một người có thể "cuộn máy tính của riêng bạn".
@John Millikin đưa ra một câu trả lời tốt, với sự phức tạp thêm của việc tính toán vào ngày đầu tiên của tháng tiếp theo.
Những điều sau đây không đặc biệt thanh lịch, nhưng để tìm ra ngày cuối cùng của tháng mà bất kỳ ngày nào đã tồn tại, bạn có thể thử:
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)
. Bạn muốn tránh gọi datetime.now hai lần, trong trường hợp bạn gọi nó ngay trước nửa đêm ngày 31 tháng 12 và sau đó chỉ sau nửa đêm. Bạn sẽ nhận được 2016-01-01 thay vì 2016-12-01 hoặc 2017-01-01.
date
là một thể hiện của datetime.date
, datetime.datetime
và cũng có thể pandas.Timestamp
.
Sử dụng dateutil.relativedelta
bạn sẽ nhận được ngày cuối cùng của tháng như thế này:
from dateutil.relativedelta import relativedelta
last_date_of_month = datetime(mydate.year, mydate.month, 1) + relativedelta(months=1, days=-1)
Ý tưởng là lấy ngày đầu tiên của tháng và sử dụng relativedelta
để đi trước 1 tháng và quay lại 1 ngày để bạn có được ngày cuối cùng của tháng bạn muốn.
Một giải pháp khác là làm một cái gì đó như thế này:
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
Và sử dụng chức năng như thế này:
>>>
>>> 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)
nếu bạn sẵn sàng sử dụng thư viện bên ngoài, hãy xem http://crsmithdev.com/arrow/
Bạn có thể nhận được ngày cuối cùng của tháng với:
import arrow
arrow.utcnow().ceil('month').date()
Điều này trả về một đối tượng ngày mà sau đó bạn có thể thực hiện thao tác của mình.
Để có được ngày cuối cùng của tháng, chúng tôi làm một cái gì đó như thế này:
from datetime import date, timedelta
import calendar
last_day = date.today().replace(day=calendar.monthrange(date.today().year, date.today().month)[1])
Bây giờ để giải thích những gì chúng tôi đang làm ở đây, chúng tôi sẽ chia nó thành hai phần:
đầu tiên là lấy số ngày của tháng hiện tại mà chúng tôi sử dụng hàng tháng mà Blair Conrad đã đề cập đến giải pháp của mình:
calendar.monthrange(date.today().year, date.today().month)[1]
thứ hai là nhận được ngày cuối cùng chính nó mà chúng tôi làm với sự giúp đỡ của thay thế ví dụ
>>> date.today()
datetime.date(2017, 1, 3)
>>> date.today().replace(day=31)
datetime.date(2017, 1, 31)
và khi chúng ta kết hợp chúng như đã đề cập ở trên, chúng ta sẽ có được một giải pháp năng động.
date.replace(day=day)
để mọi người biết những gì đang xảy ra.
Trong Python 3.7 có chức năng không có giấy tờcalendar.monthlen(year, month)
:
>>> calendar.monthlen(2002, 1)
31
>>> calendar.monthlen(2008, 2)
29
>>> calendar.monthlen(2100, 2)
28
Nó tương đương với những ghi nhận calendar.monthrange(year, month)[1]
cuộc gọi .
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)
Sử dụng gấu trúc!
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)
Đối với tôi đó là cách đơn giản nhất:
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)
Cách dễ nhất (không phải nhập lịch), là lấy ngày đầu tiên của tháng tiếp theo, và sau đó trừ đi một ngày từ đó.
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
Đầu ra:
datetime.datetime(2017, 11, 30, 0, 0)
Tái bút Mã này chạy nhanh hơn so với import calendar
cách tiếp cận; xem bên dưới:
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)
ĐẦU RA:
Time Spent= 0:00:00.097814
Time Spent= 0:00:00.109791
Mã này giả định rằng bạn muốn ngày của ngày cuối cùng của tháng (nghĩa là không chỉ phần DD, mà toàn bộ ngày YYYYMMDD)
import calendar
?
Đây là một câu trả lời khác. Không có gói bổ sung cần thiết.
datetime.date(year + int(month/12), month%12+1, 1)-datetime.timedelta(days=1)
Nhận ngày đầu tiên của tháng tiếp theo và trừ đi một ngày từ nó.
Bạn có thể tự tính ngày kết thúc. logic đơn giản là trừ đi một ngày từ start_date của tháng tiếp theo. :)
Vì vậy, viết một phương thức tùy chỉnh,
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
Gọi điện thoại
end_date_of_a_month(datetime.datetime.now().date())
Nó sẽ trả về ngày kết thúc của tháng này. Vượt qua bất kỳ ngày nào cho chức năng này. trả lại cho bạn ngày kết thúc của tháng đó.
bạn có thể sử dụng relativingelta
https://dateutil.readthedocs.io/en/urdy/relativingelta.html
month_end = <your datetime value within the month> + relativedelta(day=31)
sẽ cung cấp cho bạn vào ngày cuối cùng.
Đây là giải pháp đơn giản nhất đối với tôi khi chỉ sử dụng thư viện datetime tiêu chuẩn:
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)
Điều này không giải quyết được câu hỏi chính, nhưng một mẹo hay để có được ngày cuối tuần trong tháng là sử dụng calendar.monthcalendar
, trả về một ma trận ngày, được tổ chức với thứ Hai là cột đầu tiên đến Chủ nhật là ngày cuối cùng.
# 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
Toàn bộ [0:-2]
điều là cạo sạch các cột cuối tuần và ném chúng ra ngoài. Ngày nằm ngoài tháng được biểu thị bằng 0, do đó, tối đa bỏ qua chúng một cách hiệu quả.
Việc sử dụng numpy.ravel
không phải là thực sự cần thiết, nhưng tôi ghét dựa trên ước đơn thuần mà numpy.ndarray.max
sẽ san bằng mảng nếu không nói mà trục để tính toán kết thúc.
import calendar
from time import gmtime, strftime
calendar.monthrange(int(strftime("%Y", gmtime())), int(strftime("%m", gmtime())))[1]
Đầu ra:
31
Điều này sẽ in ngày cuối cùng của bất cứ tháng nào. Trong ví dụ này là ngày 15 tháng 5 năm 2016. Vì vậy, sản lượng của bạn có thể khác, tuy nhiên sản lượng sẽ có nhiều ngày như tháng hiện tại. Tuyệt vời nếu bạn muốn kiểm tra ngày cuối cùng của tháng bằng cách chạy một công việc định kỳ hàng ngày.
Vì thế:
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
Đầu ra:
False
Trừ khi đó là ngày cuối cùng của tháng.
Nếu bạn muốn tạo chức năng nhỏ của riêng mình, đây là điểm khởi đầu tốt:
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
Đối với điều này, bạn phải biết các quy tắc cho năm nhuận:
Trong mã bên dưới 'get_last_day_of_month (dt)' sẽ cung cấp cho bạn điều này, với ngày ở định dạng chuỗi như '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 )
Cách đơn giản nhất là sử dụng datetime
và một số phép toán ngày, ví dụ trừ một ngày từ ngày đầu tiên của tháng tiếp theo:
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)
)
Ngoài ra, bạn có thể sử dụng calendar.monthrange()
để lấy số ngày trong một tháng (tính đến năm nhuận) và cập nhật ngày cho phù hợp:
import calendar, datetime
def last_day_of_month(d: datetime.date) -> datetime.date:
return d.replace(day=calendar.monthrange(d.year, d.month)[1])
Một điểm chuẩn nhanh cho thấy phiên bản đầu tiên nhanh hơn đáng kể:
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)
Đây là một phiên bản dài (dễ hiểu) nhưng đảm nhiệm những năm nhuận.
chúc mừng, 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
và bạn cũng có thể thoát khỏi if year % 400 == 0: leap_year_flag = 1
các sửa đổi nhỏ
Đây là một giải pháp dựa trên lambd python:
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)
Các next_month
lambda thấy các đại diện tuple trong ngày đầu tiên của tháng tiếp theo, và cuộn qua sang năm sau. Các month_end
lambda biến một ngày ( dte
) vào một tuple, áp dụng next_month
và tạo ra một ngày mới. Sau đó, "cuối tháng" chỉ là điểm trừ của ngày đầu tiên của tháng tiếp theo timedelta(days=1)
.