首页 文章

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

提问于
浏览
472

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

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

28 回答

  • 13

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


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

    这是另一个答案 . 无需额外包裹 .

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

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

  • 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 lambda找到下个月第一天的元组表示,并转到下一年 . month_end lambda将日期( dte )转换为元组,应用 next_month 并创建新日期 . 那么"month's end"就是下个月的第一天减去 timedelta(days=1) .

  • 844

    当我查看documentation for the calendar module时,我没有注意到这一点,但是一个名为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]
    

    似乎是最简单的方法 .

    需要明确的是, monthrange 也支持闰年:

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

    My previous answer仍然有效,但显然不是最理想的 .

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

    OUTPUT:

    Time Spent=  0:00:00.097814
    Time Spent=  0:00:00.109791
    

    此代码假定您需要该月的最后一天的日期(即,不仅仅是DD部分,而是整个YYYYMMDD日期)

  • 37

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

    然后你可以通过以下方式获得本月的最后一天:

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

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

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

    除非它是这个月的最后一天 .

  • 6

    使用 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)
    
  • 12

    如果您不想导入 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
    
  • 8

    用熊猫!

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

    编辑:见my other answer . 它有一个比这个更好的实现,我留在这里,以防有人有兴趣看到一个人如何"roll your own"计算器 .

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

    我更喜欢这种方式

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

    在下面的代码中'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 )
    
  • 0
    from datetime import timedelta
    (any_day.replace(day=1) + timedelta(days=32)).replace(day=1) - timedelta(days=1)
    
  • 3

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

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

  • 97
    import datetime
    today = datetime.datetime.today() # currentr day for date example
    last_date = today + relativedelta(day=31)
    print "Date:", last_date.date(),"Day:", last_date.date().day
    

    output:

    Date: 2018-10-31 Day: 31
    
  • 2

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

    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)
    
  • 59
    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)
    
  • 3

    这并没有解决主要问题,但是在一个月中获得最后一个工作日的一个好方法是使用 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表示,因此max有效地忽略它们 .

    numpy.ravel 的使用并不是绝对必要的,但我讨厌依赖于 numpy.ndarray.max 如果没有告诉哪个轴计算过来会使数组变平的惯例 .

  • 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
    

    并使用这样的功能:

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

    要获取本月的最后日期,我们会执行以下操作:

    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)
    

    当我们将它们组合在一起时,我们得到了一个动态的解决方案 .

  • 0
    >>> 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
    
  • 1

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

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

    如果你传递一个日期范围,你可以使用这个:

    def last_day_of_month(any_days):
        res = []
        for any_day in any_days:
            nday = any_day.days_in_month -any_day.day
            res.append(any_day + timedelta(days=nday))
        return res
    
  • 0

    我有一个简单的解决方案:

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

    你可以使用relativedelta https://dateutil.readthedocs.io/en/stable/relativedelta.html month_end = <your datetime value within the month> + relativedelta(day=31) ,这将给你最后一天 .

  • -2

    使用 relativedelta 你会得到这样的月份的最后一个日期:

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

    这个想法是在每个月的第一天使用 relativedelta 提前1个月和1天返回,这样你就可以得到你想要的月份的最后一天 .

  • -1

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

    它将返回本月的结束日期 . 将任何日期传递给此功能 . 返回该月的结束日期 .

相关问题