파이썬에서 날짜에서 한 달을 빼는 가장 간단한 방법은 무엇입니까?


99

timedelta 만 생성자에 월 인수가있는 경우. 그래서 이것을하는 가장 간단한 방법은 무엇입니까?

편집 : 나는 아래에서 지적한 것처럼 이것에 대해 너무 열심히 생각하지 않았습니다. 정말로 내가 원했던 것은 지난 달의 어느 날이든 결국은 년과 달만 잡을 것이기 때문입니다. 따라서 datetime 객체가 주어지면 이전 달에 해당하는 datetime 객체 를 반환하는 가장 간단한 방법은 무엇 입니까?

답변:


62

이 시도:

def monthdelta(date, delta):
    m, y = (date.month+delta) % 12, date.year + ((date.month)+delta-1) // 12
    if not m: m = 12
    d = min(date.day, [31,
        29 if y%4==0 and not y%400==0 else 28,31,30,31,30,31,31,30,31,30,31][m-1])
    return date.replace(day=d,month=m, year=y)

>>> for m in range(-12, 12):
    print(monthdelta(datetime.now(), m))


2009-08-06 16:12:27.823000
2009-09-06 16:12:27.855000
2009-10-06 16:12:27.870000
2009-11-06 16:12:27.870000
2009-12-06 16:12:27.870000
2010-01-06 16:12:27.870000
2010-02-06 16:12:27.870000
2010-03-06 16:12:27.886000
2010-04-06 16:12:27.886000
2010-05-06 16:12:27.886000
2010-06-06 16:12:27.886000
2010-07-06 16:12:27.886000
2010-08-06 16:12:27.901000
2010-09-06 16:12:27.901000
2010-10-06 16:12:27.901000
2010-11-06 16:12:27.901000
2010-12-06 16:12:27.901000
2011-01-06 16:12:27.917000
2011-02-06 16:12:27.917000
2011-03-06 16:12:27.917000
2011-04-06 16:12:27.917000
2011-05-06 16:12:27.917000
2011-06-06 16:12:27.933000
2011-07-06 16:12:27.933000
>>> monthdelta(datetime(2010,3,30), -1)
datetime.datetime(2010, 2, 28, 0, 0)
>>> monthdelta(datetime(2008,3,30), -1)
datetime.datetime(2008, 2, 29, 0, 0)

편집 날짜도 처리하도록 수정 되었습니다.

편집 더 간단한 계산을 지적하는 의문의 답을 참조하십시오 d.

d = min(date.day, calendar.monthrange(y, m)[1])

내가 바로이있는 경우 ((date.month+delta-1) % 12)+1작품과 수단은 if not m: m = 12제거 얻을 수 있습니다
찰스 L.

@ dan-klasson 자세히 설명해 주시겠습니까?
Jean-François Fabre

@ Jean-FrançoisFabre 첫 번째는 간단하지 않습니다. 또한 datetime 및 timedelta를 사용하여 쉽게 수행 할 수 있습니다.
dan-klasson

예, OP 편집 후 dt - timedelta(days=dt.day)임의의 개월 수를 뺄 수 있기를 원했던 것처럼 들리지만 원래 표현한대로 원하는 것을 수행 할 수 있음이 분명해 졌습니다.
Duncan

183

타사 dateutil모듈을 사용할 수 있습니다 ( 여기에 PyPI 항목 ).

import datetime
import dateutil.relativedelta

d = datetime.datetime.strptime("2013-03-31", "%Y-%m-%d")
d2 = d - dateutil.relativedelta.relativedelta(months=1)
print d2

산출:

2013-02-28 00:00:00

param monthmonthsdateutil 과 혼동됩니다 . PARAM 빼기는 month작동하지 않지만 months작품 In [23]: created_datetime__lt - relativedelta(months=1) Out[23]: datetime.datetime(2016, 11, 29, 0, 0, tzinfo=<StaticTzInfo 'Etc/GMT-8'>) In [24]: created_datetime__lt - relativedelta(month=1) Out[24]: datetime.datetime(2016, 1, 29, 0, 0, tzinfo=<StaticTzInfo 'Etc/GMT-8'>)
인 Simin 지에

1
@SiminJie : 사용 months하면 1 개월 차이가 나는 것 같아요 . 를 사용 month하면 입력 한 달에 관계없이 월이 1 (예 : 1 월)로 설정됩니다.
Frank Meulenaar 2011

70

원래 질문을 "전월의 모든 datetime 객체"로 편집 한 후 해당 월의 1 일에서 1 일을 빼면 매우 쉽게 수행 할 수 있습니다.

from datetime import datetime, timedelta

def a_day_in_previous_month(dt):
   return dt.replace(day=1) - timedelta(days=1)

4
당신은 사용할 수 있습니다dt.replace(day=1) - timedelta(1)
JFS

3
또는dt - timedelta(days=dt.day)
SergiyKolesnikov

23

Duncan의 답변 에 대한 변형 (댓글 할만한 평판이 충분하지 않음)은 calendar.monthrange를 사용하여 해당 월의 마지막 날 계산을 극적으로 단순화합니다.

import calendar
def monthdelta(date, delta):
    m, y = (date.month+delta) % 12, date.year + ((date.month)+delta-1) // 12
    if not m: m = 12
    d = min(date.day, calendar.monthrange(y, m)[1])
    return date.replace(day=d,month=m, year=y)

Python에서 이달의 마지막 날 가져 오기의 월간 정보


22

벡터화 된 pandas 솔루션은 매우 간단합니다.

df['date'] - pd.DateOffset(months=1)


감사합니다! 날짜 세트에 한 달을 쉽게 추가 / 빼는 데 도움이되었습니다!
Mateus da Silva Teixeira

사용할 수 있으면 좋습니다 pandas. 감사!
igorkf

17

timedelta 만 생성자에 월 인수가있는 경우. 그래서 이것을하는 가장 간단한 방법은 무엇입니까?

예를 들어 3 월 30 일 날짜에서 한 달을 빼면 결과가 어떻게됩니까? 이것이 달을 더하거나 빼는 문제입니다. 달은 길이가 다릅니다! 어떤 경우에는 예외가 적절하고 다른 경우에는 "이전 달의 마지막 날"을 사용해도 괜찮습니다 (하지만 한 달을 뺀 다음 한 달을 더하는 것이 전체적으로 작동하지 않는 것은 아닙니다 !). , 다른 경우에는 날짜 외에도 사실에 대한 몇 가지 표시를 유지하고 싶을 것입니다. 예를 들어 "2 월 28 일을 말하고 있지만 2 월 30 일이 존재한다면 정말로 원할 것입니다." 그것은 다시 일을 바로 잡을 수 있습니다 (그리고 후자는 분명히 데이터와 s / thing 다른 것을 포함하는 커스텀 클래스를 필요로합니다).

모든 애플리케이션에 허용되는 실제 솔루션은있을 수 없으며,이 비참한 작업의 의미에 대한 특정 앱의 요구 사항을 알려주지 않았으므로 여기에서 제공 할 수있는 더 많은 도움이 없습니다.


당신이 절대적으로 옳습니다. timedelta가 그것에 대해 논쟁하는 것에 대해 농담했습니다. 몇 시간 또는 몇 분 동안 논쟁을하지 않는 데 동일한 논리가 적용되는지 궁금합니다. 기술적으로 하루는 정확히 24 시간이 아닙니다.
Bialecki

PHP 2 월 28 일에 2 일을 추가하여이를 처리하고 3 월 2 일로 이동합니다. 이것에 대한 규칙이 있습니다. 빨리 찾아 보겠습니다
NullUserException 2010-08-06

환전 날짜를 계산하는 경우 훨씬 더 흥미로워집니다. 예를 들어 향후 3 개월 또는 6 개월 후의 날짜를 찾아야 할 수도 있지만 두 국가에서 근무일이어야합니다 (이슬람 국가에서는 금요일이 아님). 어느 나라에서도 은행 휴무일이 아닙니다.
Duncan

@Bialecki : datetime모듈은 하루가 정확히 24 시간이라고 가정합니다 (윤초 없음)
jfs

8

간단한 방법은 Pandas의 DateOffset을 다음과 같이 사용하는 것입니다.

import pandas as pd
date_1 = pd.to_datetime("2013-03-31", format="%Y-%m-%d") - pd.DateOffset(months=1)

결과는 datetime 객체가됩니다.


2
이것이 가장 직관적 인 솔루션입니다
Kots

5

원하는 것이 지난 달의 어느 날이든, 가장 간단한 방법은 현재 날짜에서 일 수를 빼는 것입니다. 그러면 지난 달의 마지막 날이됩니다.

예를 들어, 어떤 날짜로 시작 :

>>> import datetime                                                                                                                                                                 
>>> today = datetime.date.today()                                                                                                                                                   
>>> today
datetime.date(2016, 5, 24)

현재 날짜의 날짜를 빼면 다음을 얻습니다.

>>> last_day_previous_month = today - datetime.timedelta(days=today.day)
>>> last_day_previous_month
datetime.date(2016, 4, 30)

이것은 지난달 어느 날의 단순화 된 필요에 충분합니다.

그러나 이제 당신은 그것을 가지고, 당신은 또한 당신이 시작한 같은 날을 포함하여 그 달의 어느 날이든 얻을 수 있습니다 (즉, 한 달을 빼는 것과 거의 같거나 같음) :

>>> same_day_last_month = last_day_previous_month.replace(day=today.day)
>>> same_day_last_month
datetime.date(2016, 4, 24)

물론, 30 일 월 31 일 또는 2 월에서 누락 된 날 (윤년 관리)에주의해야하지만, 그렇게하기도 쉽습니다.

>>> a_date = datetime.date(2016, 3, 31)                                                                                                                                             
>>> last_day_previous_month = a_date - datetime.timedelta(days=a_date.day)
>>> a_date_minus_month = (
...     last_day_previous_month.replace(day=a_date.day)
...     if a_date.day < last_day_previous_month.day
...     else last_day_previous_month
... )
>>> a_date_minus_month
datetime.date(2016, 2, 29)

1

저는 4 분기가 10 월 1 일에 시작되는 정부 회계 연도에 이것을 사용합니다. 참고 날짜를 분기로 변환하고 실행 취소합니다.

import pandas as pd

df['Date'] = '1/1/2020'
df['Date'] = pd.to_datetime(df['Date'])              #returns 2020-01-01
df['NewDate'] = df.Date - pd.DateOffset(months=3)    #returns 2019-10-01 <---- answer

# For fun, change it to FY Quarter '2019Q4'
df['NewDate'] = df['NewDate'].dt.year.astype(str) + 'Q' + df['NewDate'].dt.quarter.astype(str)

# Convert '2019Q4' back to 2019-10-01
df['NewDate'] = pd.to_datetime(df.NewDate)

0

다음은이 를 수행하는 몇 가지 코드 입니다. 직접 시도해 보지 않았습니다 ...

def add_one_month(t):
    """Return a `datetime.date` or `datetime.datetime` (as given) that is
    one month earlier.

    Note that the resultant day of the month might change if the following
    month has fewer days:

        >>> add_one_month(datetime.date(2010, 1, 31))
        datetime.date(2010, 2, 28)
    """
    import datetime
    one_day = datetime.timedelta(days=1)
    one_month_later = t + one_day
    while one_month_later.month == t.month:  # advance to start of next month
        one_month_later += one_day
    target_month = one_month_later.month
    while one_month_later.day < t.day:  # advance to appropriate day
        one_month_later += one_day
        if one_month_later.month != target_month:  # gone too far
            one_month_later -= one_day
            break
    return one_month_later

def subtract_one_month(t):
    """Return a `datetime.date` or `datetime.datetime` (as given) that is
    one month later.

    Note that the resultant day of the month might change if the following
    month has fewer days:

        >>> subtract_one_month(datetime.date(2010, 3, 31))
        datetime.date(2010, 2, 28)
    """
    import datetime
    one_day = datetime.timedelta(days=1)
    one_month_earlier = t - one_day
    while one_month_earlier.month == t.month or one_month_earlier.day > t.day:
        one_month_earlier -= one_day
    return one_month_earlier

0

월이 1-12 인 (년, 월) 튜플이 주어지면 다음을 시도하십시오.

>>> from datetime import datetime
>>> today = datetime.today()
>>> today
datetime.datetime(2010, 8, 6, 10, 15, 21, 310000)
>>> thismonth = today.year, today.month
>>> thismonth
(2010, 8)
>>> lastmonth = lambda (yr,mo): [(y,m+1) for y,m in (divmod((yr*12+mo-2), 12),)][0]
>>> lastmonth(thismonth)
(2010, 7)
>>> lastmonth( (2010,1) )
(2009, 12)

매년 12 개월이 있다고 가정합니다.


0
def month_sub(year, month, sub_month):
    result_month = 0
    result_year = 0
    if month > (sub_month % 12):
        result_month = month - (sub_month % 12)
        result_year = year - (sub_month / 12)
    else:
        result_month = 12 - (sub_month % 12) + month
        result_year = year - (sub_month / 12 + 1)
    return (result_year, result_month)

>>> month_sub(2015, 7, 1)    
(2015, 6)
>>> month_sub(2015, 7, -1)
(2015, 8)
>>> month_sub(2015, 7, 13)
(2014, 6)
>>> month_sub(2015, 7, -14)
(2016, 9)

0

다음 코드를 사용하여 특정 날짜에서 n 개월을 되돌 렸습니다.

your_date =  datetime.strptime(input_date, "%Y-%m-%d")  #to convert date(2016-01-01) to timestamp
start_date=your_date    #start from current date

#Calculate Month
for i in range(0,n):    #n = number of months you need to go back
    start_date=start_date.replace(day=1)    #1st day of current month
    start_date=start_date-timedelta(days=1) #last day of previous month

#Calculate Day
if(start_date.day>your_date.day):   
    start_date=start_date.replace(day=your_date.day)            

print start_date

예 : 입력 날짜 = 28/12/2015 6 개월 전 날짜를 계산합니다.

I) CALCULATE MONTH :이 단계는 시작일을 2015 년 6 월 30 일로 제공합니다.
참고 계산 단계 달 단계 후 필요한 달의 마지막 날을 얻을 것이다.

II) CALCULATE DAY : 조건 if (start_date.day> your_date.day) 는 input_date의 날짜가 필요한 달에 있는지 확인합니다. 입력 날짜가 31 (또는 30)이고 필요한 월이 31 (또는 2 월의 경우 30) 미만인 조건을 처리합니다. 윤년 사건도 처리합니다 (2 월). 이 단계 후에는 28/06/2015로 결과가 표시됩니다.

이 조건이 충족되지 않으면 start_date는 이전 달의 마지막 날짜로 유지됩니다. 따라서 입력 날짜로 2015 년 12 월 31 일을 제공하고 6 개월 전 날짜를 원하면 30/06/2015를 제공합니다.


0

아래 주어진 함수를 사용하여 X 개월 전후의 날짜를 얻을 수 있습니다.

datetime 가져 오기 날짜부터

def next_month (주어진 _ 날짜, 월) :
    yyyy = int (((given_date.year * 12 + given_date.month) + month) / 12)
    mm = int (((주어진 _ 날짜. 년 * 12 + 주어진 _ 일. 월) + 월) % 12)

    mm == 0 인 경우 :
        yyyy-= 1
        mm = 12

    return given_date.replace (year = yyyy, month = mm)


__name__ == "__main__"인 경우 :
    오늘 = date.today ()
    인쇄 (오늘)

    mm in [-12, -1, 0, 1, 2, 12, 20] :
        next_date = next_month (오늘, mm)
        인쇄 (다음 _ 날짜)

0

이 답변은 매우 읽기 쉽습니다.

def month_delta(dt, delta):
    year_delta, month = divmod(dt.month + delta, 12)

    if month == 0:
        # convert a 0 to december
        month = 12
        if delta < 0:
            # if moving backwards, then it's december of last year
            year_delta -= 1

    year = dt.year + year_delta

    return dt.replace(month=month, year=year)

for delta in range(-20, 21):
    print(delta, "->", month_delta(datetime(2011, 1, 1), delta))

-20 -> 2009-05-01 00:00:00
-19 -> 2009-06-01 00:00:00
-18 -> 2009-07-01 00:00:00
-17 -> 2009-08-01 00:00:00
-16 -> 2009-09-01 00:00:00
-15 -> 2009-10-01 00:00:00
-14 -> 2009-11-01 00:00:00
-13 -> 2009-12-01 00:00:00
-12 -> 2010-01-01 00:00:00
-11 -> 2010-02-01 00:00:00
-10 -> 2010-03-01 00:00:00
-9 -> 2010-04-01 00:00:00
-8 -> 2010-05-01 00:00:00
-7 -> 2010-06-01 00:00:00
-6 -> 2010-07-01 00:00:00
-5 -> 2010-08-01 00:00:00
-4 -> 2010-09-01 00:00:00
-3 -> 2010-10-01 00:00:00
-2 -> 2010-11-01 00:00:00
-1 -> 2010-12-01 00:00:00
0 -> 2011-01-01 00:00:00
1 -> 2011-02-01 00:00:00
2 -> 2011-03-01 00:00:00
3 -> 2011-04-01 00:00:00
4 -> 2011-05-01 00:00:00
5 -> 2011-06-01 00:00:00
6 -> 2011-07-01 00:00:00
7 -> 2011-08-01 00:00:00
8 -> 2011-09-01 00:00:00
9 -> 2011-10-01 00:00:00
10 -> 2011-11-01 00:00:00
11 -> 2012-12-01 00:00:00
12 -> 2012-01-01 00:00:00
13 -> 2012-02-01 00:00:00
14 -> 2012-03-01 00:00:00
15 -> 2012-04-01 00:00:00
16 -> 2012-05-01 00:00:00
17 -> 2012-06-01 00:00:00
18 -> 2012-07-01 00:00:00
19 -> 2012-08-01 00:00:00
20 -> 2012-09-01 00:00:00

0

짧막 한 농담 ?

previous_month_date = (current_date - datetime.timedelta(days=current_date.day+1)).replace(day=current_date.day)


0

내가 시도한 가장 간단한 방법

from datetime import datetime
from django.utils import timezone





current = timezone.now()
if current.month == 1:
     month = 12
else:
     month = current.month - 1
current = datetime(current.year, month, current.day)

0

얼마 전에 나는 a date또는 datetime.

주의 사항 : day새 달에 사용할 수없는 경우 실패합니다 . 나는 day == 1항상 날짜 개체에 이것을 사용합니다 .

Python 3.x :

def increment_month(d, add=1):
    return date(d.year+(d.month+add-1)//12, (d.month+add-1) % 12+1, 1)

Python 2.7의 경우 정수 나눗셈이 암시되기 때문에 //12를로 변경하십시오 /12.

최근에 스크립트가 이러한 유용한 전역을 얻기 시작했을 때 기본 파일에서 이것을 사용했습니다.

MONTH_THIS = datetime.date.today()
MONTH_THIS = datetime.date(MONTH_THIS.year, MONTH_THIS.month, 1)

MONTH_1AGO = datetime.date(MONTH_THIS.year+(MONTH_THIS.month-2)//12,
                           (MONTH_THIS.month-2) % 12+1, 1)

MONTH_2AGO = datetime.date(MONTH_THIS.year+(MONTH_THIS.month-3)//12,
                           (MONTH_THIS.month-3) % 12+1, 1)

-2
import datetime
date_str = '08/01/2018'
format_str = '%d/%m/%Y'
datetime_obj = datetime.datetime.strptime(date_str, format_str)   
datetime_obj.replace(month=datetime_obj.month-1)

특별한 라이브러리가 필요없는 간단한 솔루션입니다.


2
날짜가 3 월 31 일과 같으면 작동하지 않습니다.
firecast

1
또는 1 월 1
LeandroHumb

-3

다음과 같이 두 줄로 할 수 있습니다.

now = datetime.now()
last_month = datetime(now.year, now.month - 1, now.day)

수입품 기억

from datetime import datetime

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