Calculate age on a date without day-count shortcuts
Age in completed years is a calendar comparison, not a division of elapsed days by 365. A day-count shortcut changes around leap years and does not express the rule people usually mean: subtract one from the year difference when this year’s birthday has not arrived. This example accepts a birth date and a date on which age is requested, then constructs that year’s anniversary before making the comparison.
A February 29 birthday needs a policy in a non-leap year. The function explicitly chooses February 28 as its anniversary. The two assertions demonstrate both sides of that rule: before February 28 the person is still 19, and on February 28 they are 20. Another domain may define March 1 instead, so make that choice visible and test it with stakeholders rather than inheriting it accidentally from date arithmetic.
date.replace(year=...) preserves the month and day but raises ValueError when the requested calendar date does not exist, which is why the exception is limited to constructing the anniversary. The example uses only datetime.date, available in Python 3.2 and later. Python dates use a proleptic Gregorian calendar; this is not a solution for historical calendars or for determining a date from a timezone-aware timestamp. Consult the official date.replace() documentation and date comparison rules.
AI assistance disclosure: This article was drafted with AI assistance and should be reviewed in the context of its application.
from datetime import date
def age_on(born: date, on_date: date) -> int:
try:
anniversary = born.replace(year=on_date.year)
except ValueError: # February 29 in a non-leap year
anniversary = date(on_date.year, 2, 28)
return on_date.year - born.year - (on_date < anniversary)
born = date(2004, 2, 29)
assert age_on(born, date(2024, 2, 28)) == 19
assert age_on(born, date(2024, 2, 29)) == 20
assert age_on(born, date(2025, 2, 27)) == 20
assert age_on(born, date(2025, 2, 28)) == 21
print(age_on(born, date(2025, 2, 28)))
21
Comments
Post a Comment