매월 마지막 날을 얻는 방법?


632

주어진 달의 마지막 날을 쉽게 결정하기 위해 파이썬의 표준 라이브러리를 사용하는 방법이 있습니까?

표준 라이브러리가이를 지원하지 않으면 dateutil 패키지가이를 지원합니까?

답변:


1082

나는 모듈 에 대한 문서를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)

내 이전 답변은 여전히 작동하지만 분명히 차선책입니다.


이것은 원래 질문에 대한 정답이 아닙니다! 매월 마지막 날이 토 / 일이면 어떻게 되나요?
Mahdi

8
@ mahdi : 맞습니다. 두 번째 숫자는 어떤 종류의 요일이든 관계없이 "월의 일수"== "마지막 날"입니다.
RickyA

1800 년 2 월에 잘못된 날짜를 반환합니다. 나는 그것을 얻지 못한다
sword1st


monthrange혼란스러운 이름 이라고 생각할 수는 없습니다 . 당신은 반환 생각 (first_day, last_day)하지(week_day_of_first_day, number_of_days)
Flimm

146

calendar모듈 을 가져 오지 않으려는 경우 간단한 2 단계 기능도 있습니다.

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

81

편집 : 깨끗한 솔루션에 대해서는 @Blair Conrad의 답변을 참조하십시오


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

43
나는이 청소기를 12 월에 실패하고을 today.month + 1 == 13얻는다는 사실을 제외하고는 실제로이 청소기를 호출 합니다 ValueError.
fletom

4
(today.month % 12) + 1since 12 % 120 을 사용하여 문제를 해결할 수 있습니다.
bluesmoon

한 달의 31 일에 이상한 일광 절약 시간제 스위치 (오늘은 존재하지 않지만 미래는 다를 수 있음)는 23 일의 길이로 해당 달의 31 일을 렌더링 할 수 있으므로 하루를 빼면 30 일 23:00:00에 끝납니다. 그건 끔찍한 일이지만 접근 방식이 좋지 않다는 것을 보여줍니다.
Alfe

50

이것은 실제로 꽤 쉽습니다 dateutil.relativedelta(pip 용 python-datetutil 패키지). 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)

7
나는 개인적으로 relativedelta (months = + 1, seconds = -1)를
좋아한다

네가 틀렸어. datetime(2014, 2, 1) + relativedelta(days=31)주는 datetime(2014, 3, 4, 0, 0)...
Emmanuel

9
당신은 = 대신 일의 = 일을 사용
빈스 스파이에게

@BenH 그것은 처음에 months추가 된 다음 seconds빼기를 희망하는 것입니다 (확실하지 않습니다) . 그들은 **kwargs내가 그것에 의존하지 않고 일련의 개별 작업을 수행하기 때문에 전달됩니다 now + relative(months=+1) + relative(day=1) + relative(days=-1).
Alfe

last_day = (<datetime_object> + relativedelta(day=31)).day
user12345

44

편집 : 내 다른 대답을 참조하십시오 . 이것은이 것보다 더 나은 구현을 가지고 있는데, 누군가가 자신의 계산기를 어떻게 굴릴 수 있는지 알고 싶은 경우를 대비하여 여기에 남겨둔다.

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

어리석게 들리지만 이와 비슷한 달의 첫날은 어떻게 얻습니까?
Kishan

10
항상 1이 아닙니까?
블레어 콘래드

그래도 혼란스러워서 이렇게 생겼다 : start_date = date (datetime.now (). year, datetime.now (). month, 1)
Kishan

4
today = datetime.date.today(); start_date = today.replace(day=1). 12 월 31 일 자정 직전과 자정 직후에 호출 한 경우 datetime.now를 두 번 호출하지 않도록하고 싶습니다. 2016-12-01 또는 2017-01-01 대신 2016-01-01을 받게됩니다.
블레어 콘래드

이것은 datetime 인스턴스를 이해하고 반환하는 데 매우 간단하며 많은 경우에 유용 할 수 있습니다. 또 다른 장점은 입력하면 작동한다는 것입니다 date의 인스턴스이며 datetime.date, datetime.datetime도 및 pandas.Timestamp.
길 레르 메 살로메

26

dateutil.relativedelta당신을 사용하면 다음과 같이 마지막 달의 날짜를 얻을 수 있습니다 :

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

아이디어는 달의 첫날을 가져 와서 한 relativedelta달 앞뒤로 돌아가서 원하는 달의 마지막 날을 얻는 것입니다.


13

또 다른 해결책은 다음과 같이하는 것입니다.

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)

5
너무 복잡해서 파이썬 선의 세 번째 규칙을 어 깁니다.
markuz

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

이것은 버그로 만들어진 것입니다.) 1 월 31 일로 시도
LeartS

@LeartS : 그것은 나를 위해 작동합니다. 시도하면 어떻게 되나요?
콜린 앤더슨

1
효과가있다. any_day는 1 월 31 일이고, 1을 1로 바꾸고, 1 월 1 일을 추가하고, 32 일을 더하고, 2 월 2 일을 받고, day = 1로 다시 바꾸고 2 월 1 일을받습니다. 하루를 빼면 1 월 31 일이됩니다. 문제는 무엇인가. 어떤 요일이 있습니까?
Collin Anderson 12

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

9

외부 라이브러리를 사용하려는 경우 http://crsmithdev.com/arrow/를 확인하십시오 .

그런 다음 U는 다음 달을 사용하여 마지막 날을 얻을 수 있습니다.

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

그러면 날짜 개체를 반환 한 다음 조작 할 수 있습니다.


9

매월 마지막 날짜를 얻으려면 다음과 같이하십시오.

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

이제 우리가 무엇을하고 있는지 설명하기 위해 두 부분으로 나눌 것입니다.

첫 번째는 Blair Conrad가 이미 솔루션을 언급 한 monthrange 를 사용하는 이번 달의 일 수를 얻는 것입니다.

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)

우리가 위에서 언급 한 것처럼 그것들을 결합하면 우리는 역동적 인 솔루션을 얻습니다.


이 코드는 문제를 해결하는 데 도움이 될 수 있지만 질문에 그리고 / 또는 어떻게 대답 하는지 는 설명하지 않습니다 . 이러한 추가 맥락을 제공하면 장기적인 교육 가치가 크게 향상 될 것입니다. 제발 편집 제한 및 가정이 적용되는 것을 포함하여, 설명을 추가 답변을.
Toby Speight

가장 직관적 인 것 같습니다. 두 줄을 줄이려고하면 date.replace(day=day)모든 사람들이 무슨 일이 일어나고 있는지 알 수있게 됩니다.
Adam Starrh

9

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]호출 과 같습니다 .


1
이것은 Python 3.8.1에서 작동하지 않는 것 같습니다 : AttributeError : 모듈 'calendar'에 'monthlen'속성이 없습니다
jeppoo1

1
@ jeppoo1 : 예, bpo-28292 에서 비공개로 표시되어 문서화되지 않은 기능이 필요합니다.
jfs

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

5

팬더를 사용하십시오!

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

1
pd.series.dt.is_month_end 링크를
Pablo

1
Pandas datetime 객체에는 다음과 같은 특정 방법이 있습니다.now=datetime.datetime.now(); pd_now = pd.to_datetime(now); print(pd_now.days_in_month)
Roei Bahumi

3

나를 위해 가장 간단한 방법입니다.

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)

3

가장 쉬운 방법 (달력을 가져 오지 않아도 됨)은 다음 달의 첫 날을 얻은 다음 하루에서 빼는 것입니다.

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 날짜)


왜 원하지 import calendar않습니까?
Adam Venturella

1
더 빠르기 때문입니다. 이것을 포함하도록 위의 답변을 수정했습니다.
Vishal

@ Visal은 개념을 올바르게 가지고 있지만 다음 줄은 그렇지 않습니다 :```dt.datetime (thisDate.year, (thisDate + relativedelta (months = 1)). month, 1)-dt.timedelta (days = 1)` ``특히 달이 연말에있는 경우. ```last_date_of_month = \ first_date_of_month + relativedelta (months = 1)-relativedelta (days = 1)```대신
XValidated

3

다른 대답이 있습니다. 추가 패키지가 필요하지 않습니다.

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

다음 달의 첫날을 받고 하루에서 빼십시오.


2

종료 날짜를 직접 계산할 수 있습니다. 간단한 논리는 다음 달의 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())

이 달의 종료일을 반환합니다. 이 기능에 날짜를 전달하십시오. 해당 월의 종료일을 반환합니다.



1

이것은 표준 날짜 시간 라이브러리 만 사용하는 가장 간단한 솔루션입니다.

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)

0

이것은 주요 질문을 다루지는 않지만 한 달 동안 마지막 주중 을 얻는 좋은 트릭 은을 사용 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 을 통해 계산하는 축하는 말하지 않을 경우 배열을 평평하게됩니다.


0
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

매월 마지막 날이 아닌 한.


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)

0

자신 만의 작은 기능을 만들고 싶다면 이것이 좋은 출발점입니다.

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

이를 위해 윤년의 규칙을 알아야합니다.

  • 4 년마다
  • 100 년마다를 제외하고
  • 그러나 다시 400 년마다

1
물론, 시스템 라이브러리는 이미이 데이터를 가지고 있으며, 법령에 의해 규칙을 변경해야하는 경우 라이브러리 업데이트는 다른 사람의 문제입니다.
Jasen

음, 가능하지만 가능성은 거의, 심지어 경우 - 그것은 단지 약 2000 년을 물린 것 ... en.wikipedia.org/wiki/Gregorian_calendar#Accuracy은
mathause

이 규칙은 과거 500 년 동안 작동하지 않습니다. 나는 그들이 수천 년 동안 미래에있을 것이라는 확신이 없습니다.
Jasen

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

아래 코드에서 '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

가장 간단한 방법은 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)

0

여기에 길고 이해하기 쉬운 버전이 있지만 윤년을 관리합니다.

환호, 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약간의 수정으로 제거 할 수 있습니다
canbax

-1

다음은 솔루션 기반 파이썬 람다입니다.

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람다는 내년에 걸쳐 튜플 다음 달 1 일의 표현, 그리고 롤을 찾습니다. month_end람다 날짜 (변환 dte하는 튜플)을 적용 next_month하여 새로운 날짜를 생성한다. 그런 다음 "월말"은 다음 달 첫날 빼기 timedelta(days=1)입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.