Return datetime object of previous month

Viewed 185477

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 pointed out below. Really what I wanted was any day in the last month because eventually I'm going to grab the year and month only. So given a datetime object, what's the simplest way to return any datetime object that falls in the previous month?

22 Answers

A vectorized, pandas solution is very simple:

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

I think the simple way is to use DateOffset from Pandas like so:

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

The result will be a Timestamp object

Returns last day of last month:

>>> import datetime
>>> datetime.datetime.now() - datetime.timedelta(days=datetime.datetime.now().day)
datetime.datetime(2020, 9, 30, 14, 13, 15, 67582)

Returns the same day last month:

>>> x = datetime.datetime.now() - datetime.timedelta(days=datetime.datetime.now().day)
>>> x.replace(day=datetime.datetime.now().day)
datetime.datetime(2020, 9, 7, 14, 22, 14, 362421)

For most use cases, what about

from datetime import date

current_date =date.today()
current_month = current_date.month
last_month = current_month - 1 if current_month != 1 else 12  
today_a_month_ago = date(current_date.year, last_month, current_date.day)

That seems the simplest to me.

Note: I've added the second to last line so that it would work if the current month is January as per @Nick's comment

Note 2: In most cases, if the current date is the 31st of a given month the result will be an invalid date as the previous month would not have 31 days (Except for July & August), as noted by @OneCricketeer

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)

One liner ?

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

Simplest Way that i have tried Just now

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)

Some time ago I came across the following algorithm which works very well for incrementing and decrementing months on either a date or datetime.

CAVEAT: This will fail if day is not available in the new month. I use this on date objects where day == 1 always.

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)

For Python 2.7 change the //12 to just /12 since integer division is implied.

I recently used this in a defaults file when a script started to get these useful globals:

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

You could do it in two lines like this:

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

remember the imports

from datetime import datetime
Related