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

如果标准库不支持,dateutil包是否支持此功能?


当前回答

我的方法:

def get_last_day_of_month(mon: int, year: int) -> str:
    '''
    Returns last day of the month.
    '''

    ### Day 28 falls in every month
    res = datetime(month=mon, year=year, day=28)
    ### Go to next month
    res = res + timedelta(days=4)
    ### Subtract one day from the start of the next month
    res = datetime.strptime(res.strftime('%Y-%m-01'), '%Y-%m-%d') - timedelta(days=1)

    return res.strftime('%Y-%m-%d')
>>> get_last_day_of_month(mon=10, year=2022)
... '2022-10-31'

其他回答

最简单的方法是使用日期时间和一些日期数学,例如从下个月的第一天减去一天:

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()获取一个月的天数(考虑闰年)并相应地更新日期:

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)

你可以使用relativeltahttps://dateutil.readthedocs.io/en/stable/relativedelta.htmlmonth_end=<您当月的datetime值>+relativelta(day=31)这将给你最后一天。

另一种选择是使用递归函数。

第二天是在不同的月份吗?如果是,则当前日期是该月的最后一天。如果第二天在同一个月,请使用第二天重试。

from datetime import timedelta

def last_day_of_month(date):
    if date.month != (date + timedelta(days=1)).month:
        return date
    else:
        return last_day_of_month(date + timedelta(days=1))

考虑到不同月份的天数不相等,以下是适用于每个月的标准解决方案。

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)

在上面的代码中,我们只是将一个月添加到所选日期,然后导航到该月的第一天,然后从该日期中减去一天。

如果你想制作自己的小功能,这是一个很好的起点:

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年一次