Ответы:
Я не заметил этого раньше, когда просматривал документацию по 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
поддерживает и високосные годы:
>>> from calendar import monthrange
>>> monthrange(2012, 2)
(2, 29)
Мой предыдущий ответ все еще работает, но явно неоптимальный.
28
как ответ, который является правильным, используя правила для григорианского календаря
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
(пакет 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)
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
РЕДАКТИРОВАТЬ: см. Мой другой ответ . Он имеет лучшую реализацию, чем эта, которую я оставлю здесь на всякий случай, если кому-то интересно посмотреть, как можно «свернуть свой собственный» калькулятор.
@ Джон Милликин дает хороший ответ, с дополнительным усложнением вычисления первого дня следующего месяца.
Следующее не особенно элегантно, но чтобы выяснить последний день месяца, в котором живет любая конкретная дата, вы можете попробовать:
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, если вы звоните ему до полуночи 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
для перехода на 1 месяц вперед и 1 день назад, чтобы получить последний день месяца, который вы хотели.
Другое решение было бы сделать что-то вроде этого:
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])
Теперь, чтобы объяснить, что мы делаем здесь, мы разделим его на две части:
во-первых, получаем количество дней в текущем месяце, для которых мы используем месяц, который Блэр Конрад уже упомянул о своем решении:
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
Это эквивалентно документированному calendar.monthrange(year, month)[1]
звонку .
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, но и всю дату ГГГГММДД)
import calendar
?
Вот еще один ответ. Никаких дополнительных пакетов не требуется.
datetime.date(year + int(month/12), month%12+1, 1)-datetime.timedelta(days=1)
Получите первый день следующего месяца и вычтите из него один день.
Вы можете рассчитать дату окончания самостоятельно. простая логика - вычесть день из даты начала следующего месяца. :)
Так что напишите собственный метод,
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())
Он вернет дату окончания этого месяца. Передайте любую дату этой функции. возвращает вам дату окончания этого месяца.
Вы можете использовать родственник
Аддета https://dateutil.readthedocs.io/en/stable/relativedelta.html
month_end = <your datetime value within the month> + relativedelta(day=31)
, который даст вам последний день.
Это самое простое решение для меня, использующее только стандартную библиотеку 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)
Это не решает основной вопрос, но есть один хороший трюк, чтобы получить последний день недели в месяце - использовать 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
Будет напечатан последний день текущего месяца. В этом примере это было 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
Если это не последний день месяца.
Если вы хотите сделать свою собственную маленькую функцию, это хорошая отправная точка:
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
Для этого вы должны знать правила для високосных лет:
В приведенном ниже коде «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()
чтобы получить количество дней в месяце (с учетом високосных годов) и соответственно обновить дату:
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)
Вот длинная (простая для понимания) версия, но она заботится о високосных годах.
ура, 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)
.