有没有办法使用Python的标准库轻松确定(即一个函数调用)给定月份的最后一天?
如果标准库不支持,那么dateutil包是否支持此功能?
答案 0 :(得分:910)
我在查看documentation for the calendar module时没有注意到这一点,但是名为monthrange的方法提供了以下信息:
月份(年,月)
返回指定年份和月份的月份第一天的工作日和月份的天数。
>>> import calendar
>>> calendar.monthrange(2002,1)
(1, 31)
>>> calendar.monthrange(2008,2)
(4, 29)
>>> calendar.monthrange(2100,2)
(0, 28)
这样:
calendar.monthrange(year, month)[1]
似乎是最简单的方法。
为了清楚起见,monthrange
也支持闰年:
>>> from calendar import monthrange
>>> monthrange(2012, 2)
(2, 29)
My previous answer仍然有效,但显然不是最理想的。
答案 1 :(得分:114)
如果您不想导入calendar
模块,可以使用简单的两步功能:
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)
输出:
>>> 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
答案 2 :(得分:62)
编辑:请参阅@Blair Conrad关于更清洁解决方案的答案
>>> import datetime
>>> datetime.date (2000, 2, 1) - datetime.timedelta (days = 1)
datetime.date(2000, 1, 31)
>>>
答案 3 :(得分:40)
编辑:见my other answer。它有一个比这个更好的实现,我留在这里,以防有人有兴趣看看如何“滚动你自己的”计算器。
@John Millikin给出了一个很好的答案,计算下个月的第一天会增加复杂性。以下不是特别优雅,但要弄清楚任何特定日期所在的月份的最后一天,您可以尝试:
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)
答案 4 :(得分:36)
使用dateutil.relativedelta
(包为python-datetutil for pip)实际上非常简单。 day=31
将始终始终返回该月的最后一天。
示例:
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)
答案 5 :(得分:16)
使用relativedelta
,你会得到这样的最后一个日期:
from dateutil.relativedelta import relativedelta
last_date_of_month = datetime(mydate.year, mydate.month, 1) + relativedelta(months=1, days=-1)
我们的想法是获得本月的第一天并使用relativedelta
提前1个月和1天返回,这样您就可以获得所需月份的最后一天。
答案 6 :(得分:13)
另一个解决方案是做这样的事情:
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
并使用这样的功能:
>>>
>>> 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)
答案 7 :(得分:10)
from datetime import timedelta
(any_day.replace(day=1) + timedelta(days=32)).replace(day=1) - timedelta(days=1)
答案 8 :(得分:8)
如果您愿意使用外部图书馆,请查看http://crsmithdev.com/arrow/
然后,你可以通过以下方式获取当月的最后一天:import arrow
arrow.utcnow().ceil('month').date()
这将返回一个日期对象,然后您可以进行操作。
答案 9 :(得分:8)
>>> import datetime
>>> import calendar
>>> date = datetime.datetime.now()
>>> print date
2015-03-06 01:25:14.939574
>>> print date.replace(day = 1)
2015-03-01 01:25:14.939574
>>> print date.replace(day = calendar.monthrange(date.year, date.month)[1])
2015-03-31 01:25:14.939574
答案 10 :(得分:7)
要获取当月的最后日期,我们会执行以下操作:
from datetime import date, timedelta
import calendar
last_day = date.today().replace(day=calendar.monthrange(date.today().year, date.today().month)[1])
现在解释一下我们在这里做了什么,我们将其分为两部分:
首先得到我们使用monthrange的当月的天数,Blair Conrad已经提到了他的解决方案:
calendar.monthrange(date.today().year, date.today().month)[1]
第二个是在replace例如
的帮助下获取最后一个日期>>> date.today()
datetime.date(2017, 1, 3)
>>> date.today().replace(day=31)
datetime.date(2017, 1, 31)
当我们将它们组合在一起时,我们得到了一个动态解决方案。
答案 11 :(得分:5)
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)
答案 12 :(得分:3)
对我来说,这是最简单的方法:
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)
答案 13 :(得分:3)
在Python 3.7中,有the undocumented calendar.monthlen(year, month)
function:
>>> calendar.monthlen(2002, 1)
31
>>> calendar.monthlen(2008, 2)
29
>>> calendar.monthlen(2100, 2)
28
它等效于the documented calendar.monthrange(year, month)[1]
call。
答案 14 :(得分:3)
最简单的方法(无需导入日历)是获取下个月的第一天,然后从中减去一天。
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
输出:
datetime.datetime(2017, 11, 30, 0, 0)
PS:与import calendar
方法相比,此代码运行速度更快;见下文:
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)
输出:
Time Spent= 0:00:00.097814
Time Spent= 0:00:00.109791
此代码假定您需要该月最后一天的日期(即,不仅仅是DD部分,而是整个YYYYMMDD日期)
答案 15 :(得分:2)
您可以自己计算结束日期。简单的逻辑是从下个月的start_date中减去一天。 :)
所以写一个自定义方法,
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
致电,
end_date_of_a_month(datetime.datetime.now().date())
它将返回本月的结束日期。将任何日期传递给此功能。返回该月的结束日期。
答案 16 :(得分:2)
这是另一个答案。不需要额外的程序包。
datetime.date(year + int(month/12), month%12+1, 1)-datetime.timedelta(days=1)
获取下个月的第一天并从中减去一天。
答案 17 :(得分:1)
如果你想制作自己的小功能,这是一个很好的起点:
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
为此你必须知道闰年的规则:
答案 18 :(得分:1)
对我来说更简单的方法是使用熊猫(两行解决方案):
from datetime import datetime
import pandas as pd
firstday_month = datetime(year, month, 1)
lastday_month = firstday_month + pd.offsets.MonthEnd(1)
另一种方法是:取一个月的第一天,然后加上一个月并打折一天:
from datetime import datetime
import pandas as pd
firstday_month = datetime(year, month, 1)
lastday_month = firstday_month + pd.DateOffset(months=1) - pd.DateOffset(days=1)
答案 19 :(得分:1)
到目前为止,我发现的最简单,最可靠的方法是:
from datetime import datetime
import calendar
days_in_month = calendar.monthrange(2020, 12)[1]
end_dt = datetime(2020, 12, days_in_month)
答案 20 :(得分:1)
您可以使用relativedelta
https://dateutil.readthedocs.io/en/stable/relativedelta.html
month_end = <your datetime value within the month> + relativedelta(day=31)
那会给你最后一天。
答案 21 :(得分:1)
这不能解决主要问题,但是在一个月内获得最后一个工作日的一个好方法是使用calendar.monthcalendar
,它返回一个日期矩阵,以星期一组织为第一列到星期日为最后一列。
# 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
整个[0:-2]
事情是削减周末列并将它们扔出去。超出月份的日期用0表示,因此max有效地忽略它们。
numpy.ravel
的使用并非绝对必要,但我讨厌依赖仅仅约定 numpy.ndarray.max
如果没有告诉哪个轴计算过来会使数组变平。
答案 22 :(得分:1)
我更喜欢这种方式
import datetime
import calendar
date=datetime.datetime.now()
month_end_date=datetime.datetime(date.year,date.month,1) + datetime.timedelta(days=calendar.monthrange(date.year,date.month)[1] - 1)
答案 23 :(得分:1)
使用熊猫!
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
答案 24 :(得分:0)
如果你传递了一个日期范围,你可以使用它:
def last_day_of_month(any_days):
res = []
for any_day in any_days:
nday = any_day.days_in_month -any_day.day
res.append(any_day + timedelta(days=nday))
return res
答案 25 :(得分:0)
在下面的代码中,'get_last_day_of_month(dt)'将为您提供此日期,日期格式为“ 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 )
答案 26 :(得分:0)
这是仅使用标准日期时间库对我来说最简单的解决方案:
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)
答案 27 :(得分:0)
要仅用datetime
来获取月份的最后一天,可以使用以下简单功能:
import datetime
def last_day_of_month(d: datetime.date) -> datetime.date:
return d.replace(month=d.month % 12 + 1, day=1) - datetime.timedelta(days=1)
您也可以使用calendar.monthrange()
来获取月份中的天数并相应地更新日期,尽管在我的测试中,这似乎比以前的版本要慢:
import calendar, datetime
def last_day_of_month(d: datetime.date) -> datetime.date:
return d.replace(day=calendar.monthrange(d.year, d.month)[1])
答案 28 :(得分:0)
这里是一个很长的(易于理解的)版本,但是照顾了leap年。
欢呼声, JK
body
答案 29 :(得分:0)
import calendar
from time import gmtime, strftime
calendar.monthrange(int(strftime("%Y", gmtime())), int(strftime("%m", gmtime())))[1]
输出:
31
这将打印当月的最后一天。在此示例中,它是2016年5月15日。因此您的输出可能不同,但输出将是当前月份的天数。如果您想通过运行每日cron作业来检查当月的最后一天,那就太棒了。
所以:
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
输出:
False
除非是本月的最后一天。
答案 30 :(得分:0)
如何更简单:
import datetime
now = datetime.datetime.now()
datetime.date(now.year, 1 if now.month==12 else now.month+1, 1) - datetime.timedelta(days=1)
答案 31 :(得分:0)
考虑到不同月份的天数不相等,这是每个月都可以使用的标准解决方案。
import datetime
ref_date = datetime.today() # or what ever specified date
end_date_of_month = datetime.strptime(datetime.strftime(ref_date + relativedelta(months=1), '%Y-%m-01'),'%Y-%m-%d') + relativedelta(days=-1)
在上面的代码中,我们只是将一个月添加到我们选择的日期,然后导航到该月的第一天,然后从该日期减去一天。
答案 32 :(得分:-1)
这是基于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找到下个月第一天的元组表示,并转到下一年。 month_end
lambda将日期(dte
)转换为元组,应用next_month
并创建新日期。那么&#34;月结束&#34;只是下个月的第一天减去timedelta(days=1)
。
答案 33 :(得分:-3)
我希望,它非常有用..试试这个..我们必须要导入一些包
import time
from datetime import datetime, date
from datetime import timedelta
from dateutil import relativedelta
start_date = fields.Date(
string='Start Date',
required=True,
)
end_date = fields.Date(
string='End Date',
required=True,
)
_defaults = {
'start_date': lambda *a: time.strftime('%Y-%m-01'),
'end_date': lambda *a: str(datetime.now() + relativedelta.relativedelta(months=+1, day=1, days=-1))[:10],
}
答案 34 :(得分:-8)
我有一个简单的解决方案:
import datetime
datetime.date(2012,2, 1).replace(day=1,month=datetime.date(2012,2,1).month+1)-timedelta(days=1)
datetime.date(2012, 2, 29)