在Python中获取本月的最后一天

有没有一种方法使用Python的标准库来轻松确定(即一个函数调用)给定月份的最后一天?

如果标准库不支持,dateutil包是否支持这个?

之前我在查看日历模块的文档时没有注意到这一点,但名为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] 

似乎是最简单的方法。

为了清楚monthrangemonthrange支持闰年:

 >>> from calendar import monthrange >>> monthrange(2012, 2) (2, 29) 

我以前的答案仍然有效,但显然是不理想的。

如果你不想导入calendar模块,一个简单的两步function也可以是:

 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 

编辑:见@Blair康拉德的答案更干净的解决scheme


 >>> import datetime >>> datetime.date (2000, 2, 1) - datetime.timedelta (days = 1) datetime.date(2000, 1, 31) >>> 

编辑:看到我的其他答案 。 它有比这更好的实现,我离开这里,以防万一有人想看看如何“自己动手”计算器。

约翰·米利肯给出了一个很好的答案,计算下个月的第一天会增加复杂性。

以下不是特别优雅,但要找出任何给定date所在月份的最后一天,您可以尝试:

 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) 

这实际上很容易与dateutil.relativedelta (软件包python-datetutil为点)。 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) 

另一个解决办法是做这样的事情:

 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 

并使用这样的function:

 >>> >>> 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) 

使用relativedelta你会得到像这样的月份的最后date:

 from dateutil.relativedelta import relativedelta last_date_of_month = datetime(mydate.year,mydate.month,1)+relativedelta(months=1,days=-1) 

这个想法是获得一个月的第一天,并使用relativedelta提前1个月和1天后,所以你会得到你想要的月份的最后一天。

 from datetime import timedelta (any_day.replace(day=1) + timedelta(days=32)).replace(day=1) - timedelta(days=1) 
 >>> 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 
 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) 

对我来说这是最简单的方法:

 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) 

如果您愿意使用外部库,请查看http://crsmithdev.com/arrow/

然后你可以得到这个月的最后一天:

 import arrow arrow.utcnow().ceil('month').date() 

这将返回一个date对象,然后您可以进行操作。

这并没有解决主要问题,但是在一个月内得到最后一个工作日的一个很好的方法是使用calendar.monthcalendar ,它返回一个datematrix,星期一作为第一列到最后一个星期日。

 # 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]事情是刮掉周末的专栏,把它们扔掉。 月份以外的date用0表示,所以最大值忽略它们。

numpy.ravel的使用并不是绝对必要的,但我讨厌依靠numpy.ndarray.max这个单纯的约定 ,如果不告诉哪个轴计算结束,数组将会变平。

使用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 

我更喜欢这种方式

 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) 

你可以自己计算结束date。 简单的逻辑是从下个月的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()) 

它将返回本月的结束date。 将任何date传递给这个函数。 将返回该月的结束date。

为了得到本月的最后一天,我们做这样的事情:

 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已经提到了他的解决scheme:

 calendar.monthrange(date.today().year, date.today().month)[1] 

第二是获取最后的date本身,我们在replace的帮助下做例如

 >>> date.today() datetime.date(2017, 1, 3) >>> date.today().replace(day=31) datetime.date(2017, 1, 31) 

当我们把它们结合起来的时候,我们就会得到一个dynamic的解决scheme。

 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 

除非是这个月的最后一天。

如果你想使自己的小function,这是一个很好的起点:

 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 

为此,你必须知道闰年的规则:

  • 每四年一次
  • 每100年除外
  • 但每隔400年

我希望,这是非常有用的..尝试这种方式..我们必须导入一些包

 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], } 

我有一个简单的解决scheme:

 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)