Python: get datetime for '3 years ago today'

Question:

In Python, how do I get a datetime object for ‘3 years ago today’?

UPDATE: FWIW, I don’t care hugely about accuracy… i.e. it’s Feb 29th today, I don’t care whether I’m given Feb 28th or March 1st in my answer. Concision is more important than configurability, in this case.

Asked By: AP257

||

Answers:

In [3]: import datetime as dt

In [4]: today=dt.date.today()

In [5]: three_years_ago=today-dt.timedelta(days=3*365)

In [6]: three_years_ago
Out[6]: datetime.date(2008, 3, 1)
Answered By: unutbu
import datetime
datetime.datetime.now() - datetime.timedelta(days=3*365)
Answered By: Fábio Diniz

Subtracting 365*3 days is wrong, of course–you’re crossing a leap year more than half the time.

dt = datetime.now()
dt = dt.replace(year=dt.year-3)
# datetime.datetime(2008, 3, 1, 13, 2, 36, 274276)

ED: To get the leap-year issue right,

def subtract_years(dt, years):
    try:
        dt = dt.replace(year=dt.year-years)
    except ValueError:
        dt = dt.replace(year=dt.year-years, day=dt.day-1)
    return dt
Answered By: Glenn Maynard
def add_years(dt, years):
    try:
        result = datetime.datetime(dt.year + years, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond, dt.tzinfo)
    except ValueError:
        result = datetime.datetime(dt.year + years, dt.month, dt.day - 1, dt.hour, dt.minute, dt.second, dt.microsecond, dt.tzinfo)
    return result

>>> add_years(datetime.datetime.now(), -3)
datetime.datetime(2008, 3, 1, 12, 2, 35, 22000)
>>> add_years(datetime.datetime(2008, 2, 29), -3)
datetime.datetime(2005, 2, 28, 0, 0)
Answered By: Mark Ransom

If you need to be exact use the dateutil module to calculate relative dates

from datetime import datetime
from dateutil.relativedelta import relativedelta

three_yrs_ago = datetime.now() - relativedelta(years=3)
Answered By: Vince Spicer

Why not simply do a check for leap year before replacing the year.
This does not need any extra package or try:Except.

def years_ago(dt, years):
    if dt.month == 2 and dt.day == 29:
        dt = dt.replace(day=28)

    return dt.replace(year=dt.year - years)
Answered By: milkbread

This works to cater for leap year corner cases and non-leap years too. Because, if day = 29 and month = 2 (Feb), a non-leap year would throw a value error because there is no 29th Feb and the last day of Feb would be 28th, thus doing a -1 on the date works in a try-except block.

from datetime import datetime

last_year = datetime.today().year - 1
month = datetime.today().month
day = datetime.today().day

try:
    # try returning same date last year
    last_year_date = datetime.strptime(f"{last_year}-{month}-{day}",'%Y-%m-%d').date()
except ValueError: 
    # incase of error due to leap year, return date - 1 in last year
    last_year_date = datetime.strptime(f"{last_year}-{month}-{day-1}",'%Y-%m-%d').date()

print(last_year_date)
Answered By: shilpa sindhe

I was looking for a solution using only the standard library, and this worked for me. Note that without the check, Feb. 29th will give you a ValueError for most years. On all other days, it will give you the date for "three years ago today".

today = date.today()
day = 28 if today.month == 2 and today.day == 29 else today.day
three_years_ago = date(today.year - 3, today.month, day)
Answered By: Dominus.Vobiscum
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.