有没有办法使用Python的标准库轻松确定(即一个函数调用)给定月份的最后一天?
如果标准库不支持,那么dateutil包是否支持此功能?
我在查看日历模块的文档时没有注意到这一点,但是一个名为monthrange的方法提供了以下信息:
monthrange(year,month)
返回指定年份和月份的月份第一天的工作日和月份的天数.
>>> 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)
我之前的回答仍然有效,但显然不是最理想的.
如果您不想导入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
编辑:请参阅@Blair Conrad的答案以获得更清洁的解决方案
>>> import datetime >>> datetime.date(2000, 2, 1) - datetime.timedelta(days=1) datetime.date(2000, 1, 31)
编辑:看到我的其他答案.它有一个比这个更好的实现,我留在这里以防万一有人有兴趣看看如何"滚动你自己的"计算器.
@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)
这实际上非常简单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)
使用dateutil.relativedelta
你会得到这样的月份的最后一个日期:
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 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)
from datetime import timedelta (any_day.replace(day=1) + timedelta(days=32)).replace(day=1) - timedelta(days=1)
如果您愿意使用外部库,请访问http://crsmithdev.com/arrow/
然后你可以通过以下方式获得本月的最后一天:
import arrow arrow.utcnow().ceil('month').date()
这将返回一个日期对象,然后您可以进行操作.
>>> 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
要获取本月的最后日期,我们会执行以下操作:
from datetime import date, timedelta import calendar last_day = date.today().replace(day=calendar.monthrange(date.today().year, date.today().month)[1])
现在解释一下我们在这里做了什么,我们将它分为两部分:
首先是获得当月的天,我们使用的数量monthrange这布莱尔康拉德已经提到了他的解决方案:
calendar.monthrange(date.today().year, date.today().month)[1]
二是让我们的帮助下做的最后日期本身代替如
>>> date.today() datetime.date(2017, 1, 3) >>> date.today().replace(day=31) datetime.date(2017, 1, 31)
当我们将它们组合在一起时,我们得到了一个动态的解决方案.
在Python 3.7中,有未记录的calendar.monthlen(year, month)
函数:
>>> calendar.monthlen(2002, 1) 31 >>> calendar.monthlen(2008, 2) 29 >>> calendar.monthlen(2100, 2) 28
它等效于记录的calendar.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)