获取当月最后一天

2024-12-11 08:47:00
admin
原创
156
摘要:问题描述:有没有办法使用 Python 的标准库轻松确定(即一次函数调用)给定月份的最后一天?如果标准库不支持,那么 dateutil 包是否支持?解决方案 1:calendar.monthrange提供以下信息:calendar.monthrange (year, month)返回指定年份和月份    的月...

问题描述:

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

如果标准库不支持,那么 dateutil 包是否支持?


解决方案 1:

calendar.monthrange提供以下信息:

calendar.monthrange (year, month)返回指定年份月份
    的月份第一天的星期几和该月的天

>>> import calendar
>>> calendar.monthrange(2002, 1)
(calendar.TUESDAY, 31)

>>> calendar.monthrange(2008, 2)  # leap years are handled correctly
(calendar.FRIDAY, 29)

>>> calendar.monthrange(2100, 2)  # years divisible by 100 but not 400 aren't leap years
(calendar.MONDAY, 28)

# the module uses the Georgian calendar extended into the past and
# future, so leap days in the distant past will differ from Julian:
>>> calendar.monthrange(1100, 2)
(calendar.THURSDAY, 28)

# note also that pre-Python 3.12, the REPL renders the weekday
# as a bare integer:
>>> calendar.monthrange(2002, 1)
(1, 31)

所以:

calendar.monthrange(year, month)[1]

似乎是最简单的方法。

解决方案 2:

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

import datetime

def last_day_of_month(any_day):
    # The day 28 exists in every month. 4 days later, it's always next month
    next_month = any_day.replace(day=28) + datetime.timedelta(days=4)
    # subtracting the number of the current day brings us back one month
    return next_month - datetime.timedelta(days=next_month.day)

输出:

>>> for month in range(1, 13):
...     print(last_day_of_month(datetime.date(2022, month, 1)))
...
2022-01-31
2022-02-28
2022-03-31
2022-04-30
2022-05-31
2022-06-30
2022-07-31
2022-08-31
2022-09-30
2022-10-31
2022-11-30
2022-12-31

解决方案 3:

编辑:请参阅@Blair Conrad 的答案以获得更清晰的解决方案


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

解决方案 4:

这实际上非常容易dateutil.relativedeltaday=31将始终返回该月的最后一天:

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

pip install python-datetutil

解决方案 5:

编辑:请参阅我的其他答案。它有一个比这个更好的实现,我把它留在这里,以防有人有兴趣看看如何“滚动自己的”计算器。

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

解决方案 6:

使用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 天,这样您就可以获得所需的月份最后一天。

解决方案 7:

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

解决方案 8:

在 Python 3.8 中,有一个未记录的calendar._monthlen(year, month)函数:

>>> calendar._monthlen(2002, 1)
31
>>> calendar._monthlen(2008, 2)
29
>>> calendar._monthlen(2100, 2)
28

在 python 3.7 中,调用时calendar.monthlen(year, month)不需要 _underscore。

它相当于记录的calendar.monthrange(year, month)[1]调用。

解决方案 9:

from datetime import timedelta
(any_day.replace(day=1) + timedelta(days=32)).replace(day=1) - timedelta(days=1)

解决方案 10:

另一个解决方案是执行以下操作:

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)

解决方案 11:

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

然后您可以使用以下方式获取该月的最后一天:

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

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

解决方案 12:

为了获取月份的最后一天,我们可以这样做:

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)

当我们像上面提到的那样将它们结合起来时,我们得到了一个动态解决方案。

解决方案 13:

使用熊猫!

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

解决方案 14:

对我来说,更简单的方法是使用 pandas(两行解决方案):

    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)

解决方案 15:

这就是我的方法——只有两行的函数:

from dateutil.relativedelta import relativedelta

def last_day_of_month(date):
    return date.replace(day=1) + relativedelta(months=1) - relativedelta(days=1)

例子:

from datetime import date

print(last_day_of_month(date.today()))
>> 2021-09-30

解决方案 16:

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)

解决方案 17:

这是另一个答案。无需额外的包。

datetime.date(year + int(month/12), month%12+1, 1)-datetime.timedelta(days=1)

获取下个月的第一天并从中减去一天。

解决方案 18:

到目前为止我发现的最简单、最可靠的方法是:

from datetime import datetime
import calendar
days_in_month = calendar.monthrange(2020, 12)[1]
end_dt = datetime(2020, 12, days_in_month)

解决方案 19:

使用 dateutil.relativedelta

dt + dateutil.relativedelta.relativedelta(months=1, day=1, days=-1)

months=1并将day=1移动dt到下个月的第一天,然后days=-1将新日期移动到前一个日期,即当前月的最后一天。

解决方案 20:

您可以使用relativedelta
https://dateutil.readthedocs.io/en/stable/relativedelta.html
month_end = <your datetime value within the month> + relativedelta(day=31)
它会为您提供最后一天的信息。

解决方案 21:

对于我来说,这是最简单的解决方案,仅使用标准日期时间库:

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)

解决方案 22:

最简单的方法是使用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()来获取一个月的天数(考虑闰年)并相应地更新日期:

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)

解决方案 23:

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

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)

解决方案 24:

您可以自己计算结束日期。简单的逻辑是从下个月的开始日期中减去一天。:)

因此,编写一个自定义方法,

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

它将返回本月的结束日期。将任意日期传递给此函数。返回该月的结束日期。

解决方案 25:

最简单的方法(无需导入日历)是获取下个月的第一天,然后从中减去一天。

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

解决方案 26:

我在这里找到了一个有趣的解决方案。可以通过提供以下相对增量参数来获取月份的最后一天:和day=31( 可返回前一天的最后一秒):days=+1`seconds=-1`

import datetime
from dateutil.relativedelta import relativedelta

day_of_febuary = datetime.datetime(2022, 2, 21)
last_day_of_febuary = day_of_febuary + relativedelta(day=31, days=+1, seconds=-1)
print(last_day_of_febuary)
# Output: 2022-02-28 23:59:59

解决方案 27:

这并没有解决主要问题,但获取一个月的最后一个工作日的一个好方法是使用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会使数组变平坦。

解决方案 28:

更简单地说:

import datetime
now = datetime.datetime.now()
datetime.date(now.year, 1 if now.month==12 else now.month+1, 1) - datetime.timedelta(days=1)

解决方案 29:

这是一个较长的(易于理解的)版本,但考虑了闰年。

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]

解决方案 30:

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

除非它是该月的最后一天。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用