Development Tip

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

yourdevel 2020. 10. 17. 12:26
반응형

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


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

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


이 시도:

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

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

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

from datetime import datetime, timedelta

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

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에서 이달의 마지막 날 가져 오기의 월간 정보


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

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

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


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

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


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

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

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

저는 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)

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

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

월이 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 개월이 있다고 가정합니다.


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)

다음 코드를 사용하여 특정 날짜에서 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: Condition if(start_date.day>your_date.day) checks whether the day from input_date is present in the required month. This handles condition where input date is 31(or 30) and the required month has less than 31(or 30 in case of feb) days. It handles leap year case as well(For Feb). After this step you will get result as 28/06/2015

If this condition is not satisfied, the start_date remains the last date of the previous month. So if you give 31/12/2015 as input date and want 6 months previous date, it will give you 30/06/2015


You can use below given function to get date before/after X month.

from datetime import date

def next_month(given_date, month):
    yyyy = int(((given_date.year * 12 + given_date.month) + month)/12)
    mm = int(((given_date.year * 12 + given_date.month) + month)%12)

    if mm == 0:
        yyyy -= 1
        mm = 12

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


if __name__ == "__main__":
    today = date.today()
    print(today)

    for mm in [-12, -1, 0, 1, 2, 12, 20 ]:
        next_date = next_month(today, mm)
        print(next_date)

I think this answer is quite readable:

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

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)

Simple solution, no need for special libraries.

참고URL : https://stackoverflow.com/questions/3424899/whats-the-simplest-way-to-subtract-a-month-from-a-date-in-python

반응형