How can I find an age in python from today's date and a persons birthdate? The birthdate is a from a DateField in a Django model.
19 Answers
That can be done much simpler considering that int(True) is 1 and int(False) is 0, and tuples comparison goes from left to right:
from datetime import date
def calculate_age(born):
today = date.today()
return today.year - born.year - ((today.month, today.day) < (born.month, born.day))

- 12,498
- 4
- 43
- 49
-
8a nitpick: `date.today()` returns the date in the local timezone that may be different from the place of birth. You might need to [use timezones explicitly](http://stackoverflow.com/a/32658742/4279) – jfs Dec 11 '15 at 15:43
-
24That probably depends on your definition of "age". For all practical purposes a birthday is usually given as a date, not timezone-aware datetime (i.e., "born" is missing the details). Most people are not born at midnight sharp (so usually observe prematurely :-)), and when in a different timezone, I would assume that most people observe their birthday in the local time (that's what I do, I live 10-12h ahead of my birth place time). If "born" was a timezone-aware datetime, you could use pytz's arithmetic and normalize() - maybe of interest for an astrology software? – Danny W. Adair Dec 13 '15 at 04:26
-
2I agree completely in the context of human ages but your formula may be used in a wider context. Though I personally never celebrate my birthday even an hour earlier due to a family tradition and being a programmer it is trivial to calculate the time wherever I am. – jfs Dec 13 '15 at 16:35
-
-
It's not just that `int(True) == 1` and `int(False) == 0`, it turns out that Python allows you to add and subtract booleans from integers, so you don't even need to wrap the boolean values with `int`! TIL. `1 - True == 0` in Python 2 and 3. – Flimm Mar 10 '22 at 07:52
-
Well that's the point - as you can see there is no int() in the code. We're subtracting the boolean - the conversion (sometimes called "marshalling") is implicit. Just like you check the boolean values of integers `if amount`, no need to go `if bool(amount)`. – Danny W. Adair Mar 13 '22 at 23:36
from datetime import date
def calculate_age(born):
today = date.today()
try:
birthday = born.replace(year=today.year)
except ValueError: # raised when birth date is February 29 and the current year is not a leap year
birthday = born.replace(year=today.year, month=born.month+1, day=1)
if birthday > today:
return today.year - born.year - 1
else:
return today.year - born.year
Update: Use Danny's solution, it's better
-
2Just as a matter of principle, your `except` block should catch only the one specific exception that could be raised. – Daenyth Jun 23 '10 at 13:29
-
1
-
I even go so far as to test the message of the exception to make sure its what I am expecting. Even with the code above, there is a possibility that a ValueError is thrown, but its not the ValueError you are expecting. – Randy Syring Jul 12 '11 at 19:45
-
+ for exception but, Is there any problem in my [`def calculate_age(dob)`](http://codepad.org/gFx7lrmH) **?** I think it is quite simple. – Grijesh Chauhan Jan 21 '14 at 06:35
-
1@GrijeshChauhan: Yes, yours doesn't work. `datetime.date(2014, 1, 1)` gives -1, it should give 0. Your `today > dob` is checking if the DOB is in the past, not earlier this same year. `datetime.date.today()` includes year information, which is why I replace it with the current year in my solution. – mpen Jan 21 '14 at 23:41
-
@Mark Hmm helpful I think I got your point. On the basis of your comment (and some search) I improved my function as [`def calculate_age(dob)`](http://codepad.org/uVufrI8d). In-case if I am still missing let know, Thank you very much Mark. – Grijesh Chauhan Jan 22 '14 at 07:12
-
@GrijeshChauhan: That solution looks like it should work. Might want to try a few more dates, but I don't see any problems with it. – mpen Jan 22 '14 at 16:45
-
The previous version considered someone with DOB 2012-02-29 to be considered 1 year old on the 2013-02-28, which I don't. I've changed it so that they wouldn't be one year old until the 1st of March, which is how I see it. All tests pass. – qris Mar 14 '14 at 17:21
-
@qris: Your change was (rightfully) rejected by the community. I, however, agree so I've re-instated it. – mpen Mar 14 '14 at 19:40
-
This seems overly long for the task, and imho also not efficient (whole new date through replace(), exception handling...). Just subtract the birth year from this year, and subtract a further 1 if the month and day are in the future - see my answer below. And of course the tuple (2, 29) is greater than the tuple (2, 28)... – Danny W. Adair Mar 23 '14 at 03:41
-
from datetime import date
days_in_year = 365.2425
age = int((date.today() - birth_date).days / days_in_year)
In Python 3, you could perform division on datetime.timedelta
:
from datetime import date, timedelta
age = (date.today() - birth_date) // timedelta(days=365.2425)
-
2every fourth year is a leap year except evey hundredth year is not a leap year except every four hundredth year is a leap year. try days_in_year=365.2425 – Dan Jul 10 '13 at 14:00
-
3@Dan: the difference between Julian (`365.25`) and Gregorian calendar year (`365.2425`) is less than a day if you live less than 130 years. – jfs Mar 23 '14 at 17:30
-
5This doesn't work for *some* dates: `(date(2017, 3, 1) - date(2004, 3, 1)) / timedelta(days=365.2425)` should return `13`, but it returns `12`. Unfloored, the result is `12.999582469181433`. – href_ Mar 01 '17 at 08:37
As suggested by @[Tomasz Zielinski] and @Williams python-dateutil can do it just 5 lines.
from dateutil.relativedelta import *
from datetime import date
today = date.today()
dob = date(1982, 7, 5)
age = relativedelta(today, dob)
>>relativedelta(years=+33, months=+11, days=+16)`

- 1,519
- 15
- 25
The simplest way is using python-dateutil
import datetime
import dateutil
def birthday(date):
# Get the current date
now = datetime.datetime.utcnow()
now = now.date()
# Get the difference between the current date and the birthday
age = dateutil.relativedelta.relativedelta(now, date)
age = age.years
return age

- 6,099
- 2
- 18
- 14
-
10This does not work correctly when the birthday is on Feb. 29 and today's date is Feb. 28 (it will act as if today is Feb. 29). – Trey Hunner Mar 10 '13 at 03:22
from datetime import date
def age(birth_date):
today = date.today()
y = today.year - birth_date.year
if today.month < birth_date.month or today.month == birth_date.month and today.day < birth_date.day:
y -= 1
return y

- 2,179
- 21
- 24
-
date instance or some obj like that, docs.python.org/3/library/datetime.html#datetime.date, typo fixed. – gzerone Nov 12 '17 at 01:56
If you're looking to print this in a page using django templates, then the following might be enough:
{{ birth_date|timesince }}

- 7,431
- 3
- 30
- 35
-
5Don't use Django's `|timesince` for calculating a timedelta over several years because it does not account for leap years and thus yields inaccurate results. See Django ticket #19210 for more info on this. – jnns Nov 13 '13 at 11:39
Unfortunately, you cannot just use timedelata as the largest unit it uses is day and leap years will render you calculations invalid. Therefore, let's find number of years then adjust by one if the last year isn't full:
from datetime import date
birth_date = date(1980, 5, 26)
years = date.today().year - birth_date.year
if (datetime.now() - birth_date.replace(year=datetime.now().year)).days >= 0:
age = years
else:
age = years - 1
Upd:
This solution really causes an exception when Feb, 29 comes into play. Here's correct check:
from datetime import date
birth_date = date(1980, 5, 26)
today = date.today()
years = today.year - birth_date.year
if all((x >= y) for x,y in zip(today.timetuple(), birth_date.timetuple()):
age = years
else:
age = years - 1
Upd2:
Calling multiple calls to now()
a performance hit is ridiculous, it does not matter in all but extremely special cases. The real reason to use a variable is the risk of data incosistency.

- 5,968
- 1
- 20
- 30
-
Thank you, I found out this by doing some tests - and ended up a similar code found from AndiDog's link. – tkalve Feb 07 '10 at 17:50
-
3Strike 1: You're using datetime.datetime instead of datetime.date. Strike 2: Your code is ugly and inefficient. Calling datetime.now() **THREE** times?? Strike 3: Birthdate 29 Feb 2004 and today's date 28 Feb 2010 should return age 6, not die shrieking "ValueError: day is out of range for month". You're out! – John Machin Feb 07 '10 at 21:10
-
Sorry, your "Upd" code is even more baroque and broken than the first attempt -- nothing to do with 29 February; it fails in MANY simple cases like 2009-06-15 to 2010-07-02 ... the person is obviously a little over 1 year old but you deduct a year because the test on the days (2 >= 15) fails. And obviously you haven't tested it -- it contains a syntax error. – John Machin Feb 08 '10 at 03:46
The classic gotcha in this scenario is what to do with people born on the 29th day of February. Example: you need to be aged 18 to vote, drive a car, buy alcohol, etc ... if you are born on 2004-02-29, what is the first day that you are permitted to do such things: 2022-02-28, or 2022-03-01? AFAICT, mostly the first, but a few killjoys might say the latter.
Here's code that caters for the 0.068% (approx) of the population born on that day:
def age_in_years(from_date, to_date, leap_day_anniversary_Feb28=True):
age = to_date.year - from_date.year
try:
anniversary = from_date.replace(year=to_date.year)
except ValueError:
assert from_date.day == 29 and from_date.month == 2
if leap_day_anniversary_Feb28:
anniversary = datetime.date(to_date.year, 2, 28)
else:
anniversary = datetime.date(to_date.year, 3, 1)
if to_date < anniversary:
age -= 1
return age
if __name__ == "__main__":
import datetime
tests = """
2004 2 28 2010 2 27 5 1
2004 2 28 2010 2 28 6 1
2004 2 28 2010 3 1 6 1
2004 2 29 2010 2 27 5 1
2004 2 29 2010 2 28 6 1
2004 2 29 2010 3 1 6 1
2004 2 29 2012 2 27 7 1
2004 2 29 2012 2 28 7 1
2004 2 29 2012 2 29 8 1
2004 2 29 2012 3 1 8 1
2004 2 28 2010 2 27 5 0
2004 2 28 2010 2 28 6 0
2004 2 28 2010 3 1 6 0
2004 2 29 2010 2 27 5 0
2004 2 29 2010 2 28 5 0
2004 2 29 2010 3 1 6 0
2004 2 29 2012 2 27 7 0
2004 2 29 2012 2 28 7 0
2004 2 29 2012 2 29 8 0
2004 2 29 2012 3 1 8 0
"""
for line in tests.splitlines():
nums = [int(x) for x in line.split()]
if not nums:
print
continue
datea = datetime.date(*nums[0:3])
dateb = datetime.date(*nums[3:6])
expected, anniv = nums[6:8]
age = age_in_years(datea, dateb, anniv)
print datea, dateb, anniv, age, expected, age == expected
Here's the output:
2004-02-28 2010-02-27 1 5 5 True
2004-02-28 2010-02-28 1 6 6 True
2004-02-28 2010-03-01 1 6 6 True
2004-02-29 2010-02-27 1 5 5 True
2004-02-29 2010-02-28 1 6 6 True
2004-02-29 2010-03-01 1 6 6 True
2004-02-29 2012-02-27 1 7 7 True
2004-02-29 2012-02-28 1 7 7 True
2004-02-29 2012-02-29 1 8 8 True
2004-02-29 2012-03-01 1 8 8 True
2004-02-28 2010-02-27 0 5 5 True
2004-02-28 2010-02-28 0 6 6 True
2004-02-28 2010-03-01 0 6 6 True
2004-02-29 2010-02-27 0 5 5 True
2004-02-29 2010-02-28 0 5 5 True
2004-02-29 2010-03-01 0 6 6 True
2004-02-29 2012-02-27 0 7 7 True
2004-02-29 2012-02-28 0 7 7 True
2004-02-29 2012-02-29 0 8 8 True
2004-02-29 2012-03-01 0 8 8 True

- 81,303
- 11
- 141
- 189
-
And I recently just learned about the [leap second](https://en.wikipedia.org/wiki/Leap_second). – Bobort Jan 13 '17 at 19:15
Expanding on Danny's Solution, but with all sorts of ways to report ages for younger folk (note, today is datetime.date(2015,7,17)
):
def calculate_age(born):
'''
Converts a date of birth (dob) datetime object to years, always rounding down.
When the age is 80 years or more, just report that the age is 80 years or more.
When the age is less than 12 years, rounds down to the nearest half year.
When the age is less than 2 years, reports age in months, rounded down.
When the age is less than 6 months, reports the age in weeks, rounded down.
When the age is less than 2 weeks, reports the age in days.
'''
today = datetime.date.today()
age_in_years = today.year - born.year - ((today.month, today.day) < (born.month, born.day))
months = (today.month - born.month - (today.day < born.day)) %12
age = today - born
age_in_days = age.days
if age_in_years >= 80:
return 80, 'years or older'
if age_in_years >= 12:
return age_in_years, 'years'
elif age_in_years >= 2:
half = 'and a half ' if months > 6 else ''
return age_in_years, '%syears'%half
elif months >= 6:
return months, 'months'
elif age_in_days >= 14:
return age_in_days/7, 'weeks'
else:
return age_in_days, 'days'
Sample code:
print '%d %s' %calculate_age(datetime.date(1933,6,12)) # >=80 years
print '%d %s' %calculate_age(datetime.date(1963,6,12)) # >=12 years
print '%d %s' %calculate_age(datetime.date(2010,6,19)) # >=2 years
print '%d %s' %calculate_age(datetime.date(2010,11,19)) # >=2 years with half
print '%d %s' %calculate_age(datetime.date(2014,11,19)) # >=6 months
print '%d %s' %calculate_age(datetime.date(2015,6,4)) # >=2 weeks
print '%d %s' %calculate_age(datetime.date(2015,7,11)) # days old
80 years or older
52 years
5 years
4 and a half years
7 months
6 weeks
7 days
import datetime
Todays date
td=datetime.datetime.now().date()
Your birthdate
bd=datetime.date(1989,3,15)
Your age
age_years=int((td-bd).days /365.25)

- 5,848
- 7
- 45
- 69
Extend to Danny W. Adair Answer, to get month also
def calculate_age(b):
t = date.today()
c = ((t.month, t.day) < (b.month, b.day))
c2 = (t.day< b.day)
return t.year - b.year - c,c*12+t.month-b.month-c2

- 5,230
- 4
- 34
- 59
Here is a solution to find age of a person as either years or months or days.
Lets say a person's date of birth is 2012-01-17T00:00:00 Therefore, his age on 2013-01-16T00:00:00 will be 11 months
or if he is born on 2012-12-17T00:00:00, his age on 2013-01-12T00:00:00 will be 26 days
or if he is born on 2000-02-29T00:00:00, his age on 2012-02-29T00:00:00 will be 12 years
You will need to import datetime.
Here is the code:
def get_person_age(date_birth, date_today):
"""
At top level there are three possibilities : Age can be in days or months or years.
For age to be in years there are two cases: Year difference is one or Year difference is more than 1
For age to be in months there are two cases: Year difference is 0 or 1
For age to be in days there are 4 possibilities: Year difference is 1(20-dec-2012 - 2-jan-2013),
Year difference is 0, Months difference is 0 or 1
"""
years_diff = date_today.year - date_birth.year
months_diff = date_today.month - date_birth.month
days_diff = date_today.day - date_birth.day
age_in_days = (date_today - date_birth).days
age = years_diff
age_string = str(age) + " years"
# age can be in months or days.
if years_diff == 0:
if months_diff == 0:
age = age_in_days
age_string = str(age) + " days"
elif months_diff == 1:
if days_diff < 0:
age = age_in_days
age_string = str(age) + " days"
else:
age = months_diff
age_string = str(age) + " months"
else:
if days_diff < 0:
age = months_diff - 1
else:
age = months_diff
age_string = str(age) + " months"
# age can be in years, months or days.
elif years_diff == 1:
if months_diff < 0:
age = months_diff + 12
age_string = str(age) + " months"
if age == 1:
if days_diff < 0:
age = age_in_days
age_string = str(age) + " days"
elif days_diff < 0:
age = age-1
age_string = str(age) + " months"
elif months_diff == 0:
if days_diff < 0:
age = 11
age_string = str(age) + " months"
else:
age = 1
age_string = str(age) + " years"
else:
age = 1
age_string = str(age) + " years"
# The age is guaranteed to be in years.
else:
if months_diff < 0:
age = years_diff - 1
elif months_diff == 0:
if days_diff < 0:
age = years_diff - 1
else:
age = years_diff
else:
age = years_diff
age_string = str(age) + " years"
if age == 1:
age_string = age_string.replace("years", "year").replace("months", "month").replace("days", "day")
return age_string
Some extra functions used in the above codes are:
def get_todays_date():
"""
This function returns todays date in proper date object format
"""
return datetime.now()
And
def get_date_format(str_date):
"""
This function converts string into date type object
"""
str_date = str_date.split("T")[0]
return datetime.strptime(str_date, "%Y-%m-%d")
Now, we have to feed get_date_format() with the strings like 2000-02-29T00:00:00
It will convert it into the date type object which is to be fed to get_person_age(date_birth, date_today).
The function get_person_age(date_birth, date_today) will return age in string format.

- 25
- 4
As I did not see the correct implementation, I recoded mine this way...
def age_in_years(from_date, to_date=datetime.date.today()):
if (DEBUG):
logger.debug("def age_in_years(from_date='%s', to_date='%s')" % (from_date, to_date))
if (from_date>to_date): # swap when the lower bound is not the lower bound
logger.debug('Swapping dates ...')
tmp = from_date
from_date = to_date
to_date = tmp
age_delta = to_date.year - from_date.year
month_delta = to_date.month - from_date.month
day_delta = to_date.day - from_date.day
if (DEBUG):
logger.debug("Delta's are : %i / %i / %i " % (age_delta, month_delta, day_delta))
if (month_delta>0 or (month_delta==0 and day_delta>=0)):
return age_delta
return (age_delta-1)
Assumption of being "18" on the 28th of Feb when born on the 29th is just wrong. Swapping the bounds can be left out ... it is just a personal convenience for my code :)

- 21
- 1
Slightly modified Danny's solution for easier reading and understanding
from datetime import date
def calculate_age(birth_date):
today = date.today()
age = today.year - birth_date.year
full_year_passed = (today.month, today.day) < (birth_date.month, birth_date.day)
if not full_year_passed:
age -= 1
return age

- 1
- 1

- 783
- 1
- 12
- 17
import datetime
def age(date_of_birth):
if date_of_birth > datetime.date.today().replace(year = date_of_birth.year):
return datetime.date.today().year - date_of_birth.year - 1
else:
return datetime.date.today().year - date_of_birth.year
In your case:
import datetime
# your model
def age(self):
if self.birthdate > datetime.date.today().replace(year = self.birthdate.year):
return datetime.date.today().year - self.birthdate.year - 1
else:
return datetime.date.today().year - self.birthdate.year

- 607
- 1
- 6
- 8
A slightly more elegant solution than @DannyWAdairs solution might be to work with the .timetuple()
method [Python-doc]:
from datetime import date
def calculate_age(born):
today = date.today()
return today.year - born.year - (today.timetuple()[1:3] < born.timetuple()[1:3])
You can easily use this to generalize this further to increase its granularity to seconds, such that the age increments if it is greater than or equal to the number of seconds of that day, if born
is for example a datetime
object:
from datetime import datetime
def calculate_age_with_seconds(born):
today = datetime.now()
return today.year - born.year - (today.timetuple()[1:6] < born.timetuple()[1:6])
This will work for born
both being a date
or a datetime
object.

- 443,496
- 30
- 428
- 555
-
Once you move to datetime objects, you really also have to start considering timezones. Luckily, that's not what the question was about. See also comments on my solution. – Danny W. Adair Dec 12 '22 at 23:05
serializers.py
age = serializers.SerializerMethodField('get_age')
class Meta:
model = YourModel
fields = [..,'','birthdate','age',..]
import datetime
def get_age(self, instance):
return datetime.datetime.now().year - instance.birthdate.year

- 638
- 7
- 11
You can use Python 3 to do all this. Just run the following code and see.
# Creating a variables:
greeting = "Hello, "
name = input("what is your name?")
birth_year = input("Which year you were born?")
response = "Your age is "
# Converting string variable to int:
calculation = 2020 - int(birth_year)
# Printing:
print(f'{greeting}{name}. {response}{calculation}')

- 381
- 2
- 12
-
1Dude, come on... that wouldn't give you the right answer for 11 months of the year if your birthday was in December and you did that calculation in January, as an example ;). Not the way to go. – AppHandwerker Sep 30 '20 at 18:15