Получить последний день месяца

Есть ли способ использовать стандартную библиотеку Python, чтобы легко определить (например, один вызов функции) последний день данного месяца?

Если стандартная библиотека не поддерживает это, поддерживает ли этот пакет dateutil?

Ответ 1

Я не заметил этого раньше, когда смотрел документацию для модуля календаря, но метод под названием monthrange предоставляет следующую информацию:

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)

Мой предыдущий ответ по-прежнему работает, но явно субоптимален.

Ответ 2

Если вы не хотите импортировать модуль 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

Ответ 3

EDIT: см. ответ @Blair Conrad для более чистого решения


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

Ответ 4

EDIT: см. мой другой ответ. Он имеет лучшую реализацию, чем эта, которую я оставляю здесь на случай, если кто-то заинтересован в том, как можно "раскрутить свой" калькулятор.

@Джон Милликин дает хороший ответ с дополнительным усложнением расчета первого дня следующего месяца.

Ниже не особенно изящно, но чтобы выяснить последний день месяца, в котором проживает какая-либо дата, вы можете попробовать:

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)

Ответ 5

Это довольно легко с dateutil.relativedelta (пакет python-datetutil для 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)

Ответ 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

Другим решением было бы сделать что-то вроде этого:

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)

Ответ 8

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

Ответ 9

если вы хотите использовать внешнюю библиотеку, посмотрите http://crsmithdev.com/arrow/

Вы можете получить последний день месяца с помощью:

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

Это возвращает объект даты, который вы можете затем сделать ваши манипуляции.

Ответ 10

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

Ответ 11

Чтобы получить последнюю дату месяца, мы делаем что-то вроде этого:

from datetime import date, timedelta
import calendar
last_day = date.today().replace(day=calendar.monthrange(date.today().year, date.today().month)[1])

Теперь, чтобы объяснить, что мы делаем здесь, мы разделим его на две части:

во-первых, получаем количество дней текущего месяца, для которых мы используем диапазон месяцев, о котором Блэр Конрад уже упоминал о своем решении:

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)

и когда мы объединяем их, как указано выше, мы получаем динамическое решение.

Ответ 13

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)

Ответ 14

Для меня это самый простой способ:

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)

Ответ 15

Самый простой способ (без импорта календаря) - получить первый день следующего месяца, а затем вычесть из него день.

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)

Ответ 16

Вы сами можете рассчитать дату окончания. простая логика состоит в том, чтобы вычесть день с начала_задания следующего месяца.:)

Итак, напишите собственный метод,

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

Он вернет дату окончания этого месяца. Передайте любую дату этой функции. возвращает дату окончания этого месяца.

Ответ 17

Вот еще один ответ. Никаких дополнительных пакетов не требуется.

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

Получите первый день следующего месяца и вычтите из него один день.

Ответ 18

Используйте pandas!

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

Ответ 19

Вы можете использовать относительную month_end = <your datetime value within the month> + relativedelta(day=31) https://dateutil.readthedocs.io/en/stable/relativedelta.html month_end = <your datetime value within the month> + relativedelta(day=31), которая даст вам последний день.

Ответ 20

Это не относится к основному вопросу, но один приятный трюк, чтобы получить последний будний месяц в месяц, - это использовать 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 будет сгладить массив, если не сказать, какую ось рассчитать.

Ответ 21

Если вы хотите создать свою собственную небольшую функцию, это хорошая отправная точка:

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 лет

Ответ 22

import calendar
from time import gmtime, strftime
calendar.monthrange(int(strftime("%Y", gmtime())), int(strftime("%m", gmtime())))[1]

Вывод:

31



Это будет печатать последний день любого текущего месяца. В этом примере это было 15 мая 2016 года. Таким образом, ваш результат может быть другим, однако на выходе будет столько дней, сколько будет в текущем месяце. Отлично, если вы хотите проверить последний день месяца, выполнив ежедневное задание 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

Если это не последний день месяца.

Ответ 23

Я предпочитаю этот путь

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)

Ответ 24

Конечно стрелка не является стандартной библиотекой, но она предлагает некоторые интересные функции. Здесь ответ на этот конкретный вопрос, демонстрирующий способность стрелки делать хорошее форматирование.

>>> import arrow
>>> arrow.get(2017,2,14).ceil('month').format('dddd, Do MMMM')
'Tuesday, 28th February'

Что касается вопроса, это часть .ceil('month'), которая вычисляет последнюю дату месяца.

Ответ 25

Если вы передаете диапазон дат, вы можете использовать это:

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

Ответ 26

В приведенном ниже коде 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 )

Ответ 27

Это самое простое решение для меня, использующее только стандартную библиотеку datetime:

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)

Ответ 28

Самый простой способ - использовать datetime и некоторые математические функции, например, дату. вычтите день из первого дня следующего месяца:

import datetime

def last_day_of_month(d: datetime.date) -> datetime.date:
    return (
        d.replace(year=d.year + d.month//12, month=d.month % 12 + 1, day=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])

Ответ 29

Вот решение на основе 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).

Ответ 30

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

выход:

Date: 2018-10-31 Day: 31