Answers:
在查看该calendar
模块的文档时,我没有注意到这一点,但是称为的方法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
支持supports年:
>>> from calendar import monthrange
>>> monthrange(2012, 2)
(2, 29)
我以前的答案仍然有效,但显然不是最佳选择。
monthrange
一个令人困惑的名字。您会以为它会返回(first_day, last_day)
,而不是(week_day_of_first_day, number_of_days)
如果您不想导入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)
today.month + 1 == 13
您出现故障时失败ValueError
。
(today.month % 12) + 1
因为12 % 12
给出0” 来解决该问题
dateutil.relativedelta
(使用pip软件包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)
datetime(2014, 2, 1) + relativedelta(days=31)
给datetime(2014, 3, 4, 0, 0)
...
months
添加,然后seconds
减去的希望。由于它们是通过的,因此**kwargs
我不会依赖它,而是执行一系列单独的操作:now + relative(months=+1) + relative(day=1) + relative(days=-1)
这是明确的。
last_day = (<datetime_object> + relativedelta(day=31)).day
编辑:看到我的其他答案。它的实现比该方法更好,我留在这里是为了防止有人感兴趣地看一看如何“滚动自己的”计算器。
@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)
today = datetime.date.today(); start_date = today.replace(day=1)
。您可能要避免两次调用datetime.now,以防您在12月31日午夜之前调用它,然后在午夜之后调用它。您将获得2016-01-01而不是2016-12-01或2017-01-01。
date
是和的实例datetime.date
,则datetime.datetime
它也可以工作pandas.Timestamp
。
使用dateutil.relativedelta
您会得到这样的月份的最后日期:
from dateutil.relativedelta import relativedelta
last_date_of_month = datetime(mydate.year, mydate.month, 1) + relativedelta(months=1, days=-1)
这个想法是获取月份的第一天,并relativedelta
习惯于提前一个月再返回一天,这样您就可以获得想要的月份的最后一天。
另一个解决方案是做这样的事情:
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()
这将返回一个日期对象,您可以随后对其进行操作。
要获取该月的最后日期,我们需要执行以下操作:
from datetime import date, timedelta
import calendar
last_day = date.today().replace(day=calendar.monthrange(date.today().year, date.today().month)[1])
现在解释一下我们在这里做什么,我们将其分为两部分:
首先是获取当月的天数,我们使用Blair Conrad已经提到他的解决方案的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)
当我们按顶部所述将它们组合在一起时,便得到了动态解决方案。
date.replace(day=day)
以便每个人都知道发生了什么。
在Python 3.7中,有未记录的calendar.monthlen(year, month)
函数:
>>> calendar.monthlen(2002, 1)
31
>>> calendar.monthlen(2008, 2)
29
>>> calendar.monthlen(2100, 2)
28
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)
使用熊猫!
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)
对我来说,这是最简单的方法:
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)
最简单的方法(无需导入日历)是获取下个月的第一天,然后从中减去一天。
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日期)
import calendar
呢?
您可以自己计算结束日期。简单的逻辑是从下个月的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())
它将返回本月的结束日期。将任何日期传递给此功能。返回该月的结束日期。
您可以使用relativedelta
https://dateutil.readthedocs.io/en/stable/relativedelta.html
month_end = <your datetime value within the month> + relativedelta(day=31)
来给您最后的一天。
仅使用标准日期时间库,这对我来说是最简单的解决方案:
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)
这没有解决主要问题,但是使用一个月中的最后一个工作日的一个不错的技巧是使用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表示,因此最大值实际上会忽略它们。
使用的numpy.ravel
是不是绝对必要的,但我不喜欢依靠单纯的惯例是numpy.ndarray.max
将压平的数组,如果没有被告知哪个轴计算过。
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
除非是每月的最后一天。
如果要创建自己的小函数,这是一个很好的起点:
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
为此,您必须了解the年的规则:
在“ 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 )
最简单的方法是使用datetime
和一些日期数学,例如从下个月的第一天减去一天:
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)
)
或者,您可以calendar.monthrange()
用来获取一个月中的天数(考虑leap年)并相应地更新日期:
import calendar, datetime
def last_day_of_month(d: datetime.date) -> datetime.date:
return d.replace(day=calendar.monthrange(d.year, d.month)[1])
快速基准测试表明,第一个版本的速度明显更快:
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)
这是一个很长的版本(易于理解),但是照顾了leap年。
干杯,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
,也可以做 if year % 400 == 0: leap_year_flag = 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
拉姆达发现到明年下个月的第一天的元组表示,和卷。该month_end
拉姆达转换日期(dte
)的元组,应用next_month
和创造新的日期。然后,“月底”就是下个月的第一天减去timedelta(days=1)
。