What's the simplest way to subtract a month from a date in Python?

前端 未结 21 1763
[愿得一人]
[愿得一人] 2020-12-02 09:12

If only timedelta had a month argument in it\'s constructor. So what\'s the simplest way to do this?

EDIT: I wasn\'t thinking too hard about this as was poin

相关标签:
21条回答
  • 2020-12-02 09:23

    After the original question's edit to "any datetime object in the previous month", you can do it pretty easily by subtracting 1 day from the first of the month.

    from datetime import datetime, timedelta
    
    def a_day_in_previous_month(dt):
       return dt.replace(day=1) - timedelta(days=1)
    
    0 讨论(0)
  • 2020-12-02 09:23
    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 讨论(0)
  • 2020-12-02 09:23

    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
    
    0 讨论(0)
  • 2020-12-02 09:30

    One liner ?

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

    0 讨论(0)
  • 2020-12-02 09:31

    If all you want is any day in the last month, the simplest thing you can do is subtract the number of days from the current date, which will give you the last day of the previous month.

    For instance, starting with any date:

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

    Subtracting the days of the current date we get:

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

    This is enough for your simplified need of any day in the last month.

    But now that you have it, you can also get any day in the month, including the same day you started with (i.e. more or less the same as subtracting a month):

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

    Of course, you need to be careful with 31st on a 30 day month or the days missing from February (and take care of leap years), but that's also easy to do:

    >>> 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)
    
    0 讨论(0)
  • 2020-12-02 09:32

    I use this for government fiscal years where Q4 starts October 1st. Note I convert the date into quarters and undo it as well.

    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 讨论(0)
提交回复
热议问题