How to find difference in years between two dates?
John Machin
sjmachin at lexicon.net
Wed Jul 26 07:57:27 EDT 2006
thebjorn wrote:
> For the purpose of finding someone's age I was looking for a way to
> find how the difference in years between two dates, so I could do
> something like:
>
> age = (date.today() - born).year
>
> but that didn't work (the timedelta class doesn't have a year
> accessor).
>
> I looked in the docs and the cookbook, but I couldn't find anything, so
> I came up with:
>
> def age(born):
> now = date.today()
> birthday = date(now.year, born.month, born.day)
Bad luck if the punter was born on 29 Feb and the current year is not a
leap year.
> return now.year - born.year - (birthday > now and 1 or 0)
Holy code bloat, Batman! Try this:
return now.year - born.year - (birthday > now)
>
> i.e. calculate the "raw" years first and subtract one if he hasn't had
> his birthday yet this year... It works, but I'd rather use a standard
> and generic approach if it exists...?
>
It's the irregular-size months that cause the problems. If you can work
out the months difference, then just floor_div by 12 to get the years
difference.
Below is some code from the ancient times when everybody and his dog
each had their own date class :-)
HTH,
John
8<--- methods from a date class
def months_until(self, to_date):
"""Return number of months between from_date (self) and to_date.
"""
from_date = self
signum = 1
if from_date > to_date:
from_date, to_date = to_date, from_date
signum = -1
d1, m1, y1 = from_date.day, from_date.month, from_date.year
d2, m2, y2 = to_date.day, to_date.month, to_date.year
mdiff = (y2 - y1) * 12 + m2 - m1
if d2 < d1 and (d2 < 28 or d2 != last_day_of_month(y2, m2)):
# the test d2 < 28 is not necessary; it is an optimisation
# to avoid calling last_day_of_month unnecessarily
mdiff = mdiff - 1
return mdiff * signum
def years_until(self, to_date):
"""Return number of years between from_date (self) and to_date.
"""
md = self.months_until(to_date)
if md >= 0:
return md // 12
else:
# ensure division truncates towards zero
return -((-md) // 12)
8<--- module-level functions and constants
# days in month
_dim = (None, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
def last_day_of_month(y, m):
"""Return day (1..31) which is last day of month m in year y
"""
if m == 2:
return 28 + _leap(y)
else:
if not (1 <= m <= 12):
raise DateError, "month not in 1..12"
return _dim[m]
def _leap(y):
if y % 4: return 0
if y % 100: return 1
if y % 400: return 0
return 1
8<----
More information about the Python-list
mailing list