9

I want to calculate the difference between two datetime.date() dates in years and months.

For example;

d1 = date(2001,5,1)  
d2 = date(2012,1,1)   
d3 = date(2001,1,1)   
d4 = date(2012,5,1)   


diff1 = d2 - d1  
diff2 = d4 - d3

Desired result:

diff1 == 10 years & 8 months. 
diff2 == 11 years & 4 months.

Thanks.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Tom Fin
  • 123
  • 1
  • 1
  • 8

3 Answers3

27

If you are able to install the excellent dateutil package, you can do this:

>>> from dateutil import relativedelta as rdelta
>>> from datetime import date
>>> d1 = date(2001,5,1)
>>> d2 = date(2012,1,1)
>>> rd = rdelta.relativedelta(d2,d1)
>>> "{0.years} years and {0.months} months".format(rd)
'10 years and 8 months'
Burhan Khalid
  • 169,990
  • 18
  • 245
  • 284
  • Thanks Burhan, I tried your solution and it seems to be calculating the years and month as expected/ accurately. Thanks for the support. – Tom Fin Sep 25 '12 at 01:21
11

In python, subtracting two datetime.date objects results in a datetime.timedelta object, which has a days attribute.

Turning the number of days difference into years and months is not clearly defined; if you define a year as 365 days and a month as 30 days, you could use:

years, remainder = divmod(diff1.days, 365)
months = remainder // 30

Or, you could define average year and month lengths to be (slightly) more accurate:

avgyear = 365.2425        # pedants definition of a year length with leap years
avgmonth = 365.2425/12.0  # even leap years have 12 months
years, remainder = divmod(diff1.days, avgyear)
years, months = int(years), int(remainder // avgmonth)

With the latter calculation, your second difference comes out as 11 years and 3 months.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Totally agree that you need to define what a "difference of 1 month" really means. But being *really* picky, dividing by about 30.45 might give better results, as on average that's about how long a month is so will be more accurate over long periods. – Stu Cox Sep 24 '12 at 12:24
  • @StuCox: `365/12.0` is `30.416666666666668`, actually. Yes, you could store that value as the average month length. – Martijn Pieters Sep 24 '12 at 12:26
  • Don't forget leap years... (every 4, but not if divisible by 100, unless also divisible by 400) so 365.2425 days per year, divided by 12 = 30.436875. **This is getting silly.** – Stu Cox Sep 24 '12 at 12:34
  • @StuCox: :-P Which is where the dateutil package wins. I think my definition is good enough though. – Martijn Pieters Sep 24 '12 at 12:38
  • Thanks Martijn, sorry you are right, I was not clear about the number of days in a year/month. I want the results to be as accurate as possible. After trying both of your examples on a few occasions it gets it wrong by a month. Yes I know this is my fault for not being clear and I am sorry. Thanks, your solution works well for the most part. – Tom Fin Sep 25 '12 at 01:23
  • @TomFin: TBH I think the relativedelta solution is the best too! – Martijn Pieters Sep 25 '12 at 06:22
  • In Python 3: `years, remainder = divmod(abs(diff1), YEAR); months = remainder // (YEAR / 12)` where `YEAR = timedelta(365.2425)`. If the result is an integer number of years, months; we can ignore one day error every four years (for year=365) – jfs Aug 31 '14 at 10:10
1

timedelta objects don't have information about months, you might be better to compute the years and months directly

>>> d2.year - d1.year + (d2.month - d1.month)/12,  (d2.month - d1.month)%12
(10, 8)
>>> d4.year - d3.year + (d4.month - d3.month)/12,  (d4.month - d3.month)%12
(11, 4)
John La Rooy
  • 295,403
  • 53
  • 369
  • 502