I was working on a problem the other day that required me to calculate the age of a person in years. Rather than visiting Stack Overflow and grabbing a ready made solution I put together the following function:

``````def age(when, on=None):
if on is None:
on = datetime.date.today()
on_unix = time.mktime(on.timetuple())
when_unix = time.mktime(when.timetuple())
return int((on_unix - when_unix) / 3.15569e7)

# age of someone from today (2014/09/04)
age(date(2000, 1, 1))  # 14
age(date(1997, 9, 4))  # 17
age(date(1997, 9, 5))  # 16

# age of someone from 2014/01/01
age(date(2000, 1, 1), date(2014, 1, 1))  # 14
age(date(1997, 9, 4), date(2014, 1, 1))  # 16
age(date(1997, 9, 5), date(2014, 1, 1))  # 16``````

While this approach was working as expected, it was very slow, and I suspected it was the `time.mktime` that was the source of it. To Stack Overflow!

I found the Age from birthdate in python question and some of the solutions that were in there were overly complex for the problem at hand. I didn’t even test the speed of them because my code was much easier to read.

Then I found this beautiful piece of code and modified it to behave like my function above:

``````def age(when, on=None):
if on is None:
on = datetime.date.today()
was_earlier = (on.month, on.day) < (when.month, when.day)
return on.year - when.year - (was_earlier)``````

The magic is that `True` and `False` are automatically converted to `1` and `0` when interpreted as integers.

The performance numbers speak for themselves. Using `timeit` I called the function 100000 times. The average speed of my implementation over 5 runs was `3.164` seconds, whereas Danny’s was `0.121` seconds!