33

I am trying to calculate how old is a person in a database.
Let's suppose to have this simple table:

student(id, birth_date);

Where id is the primary key (truly the table is more complex but I have simplified it).
I want to get how much old is a single person:

select id, datediff(curdate(),birth_date) 
from student

But it returns a result in days, and not in years.I could divide it by 365:

select id, datediff(curdate(),birth_date) / 365
from student

But it returns a floating point value, and I want an integer.
So I could calculate the years:

select id, year(curdate())-year(birth_date) 
from student

But there is a problem: for instance now is May, if a person war born in June, 1970 he has still 31 years and not 32, but the expression returns 32.
I can't come out of this problem, can someone help me?

Ramy Al Zuhouri
  • 21,580
  • 26
  • 105
  • 187

9 Answers9

108

For anyone who comes across this:

another way this can be done is:

SELECT TIMESTAMPDIFF(YEAR, date_of_birth, CURDATE()) AS difference FROM student

For differences in months, replace YEAR with MONTH, and for days replace YEAR with DAY

starball
  • 20,030
  • 7
  • 43
  • 238
  • 1
    Here is the official doc of `TIMESTAMPDIFF`: https://dev.mysql.com/doc/refman/5.6/en/date-and-time-functions.html#function_timestampdiff – TonyLxc Feb 09 '18 at 20:30
18
select id, floor(datediff(curdate(),birth_date) / 365)
from student

What about flooring the result to be an integer?

Scott Bonner
  • 2,890
  • 5
  • 27
  • 28
4

Try:

SELECT 
  DATE_FORMAT(FROM_DAYS(TO_DAYS(NOW())-TO_DAYS(birth_date)), '%Y')+0
  AS age FROM student;
elias
  • 15,010
  • 4
  • 40
  • 65
  • 1
    This can be simplified as `SELECT YEAR(FROM_DAYS(TO_DAYS(NOW())-TO_DAYS("1975-04-20")));` And it correctly deals with leap years. – Schwern Jan 30 '17 at 21:05
  • Does it correctly deal with leap years though? Information regarding the actual dates are getting lost in the TO_DAYS function, and I don't see how the FROM_DAYS will possibly recover and account for the exact leap years @elias – Madhuchhanda Mandal Oct 26 '21 at 11:23
4

The accepted answer is almost correct, but can lead to wrong results.

In fact, / 365 doesn't take into consideration leap years, and can lead to falsy results if you compare a date that has the same day&month than the birthdate.

In order to be more accurate, you have to divide it by the average days in years for 4 years, aka (365 * 4) + 1 (the leap year every 4 years) => 365.25

And you will be more accurate :

select id, floor(datediff(curdate(),birth_date) / 365.25) from student

Tested for one of my project and it's working.

Cyril N.
  • 38,875
  • 36
  • 142
  • 243
  • Isn't datediff(curdate(),birth_date casted to a floating point? – Ramy Al Zuhouri Dec 21 '12 at 12:34
  • I couldn't say for sure, but I tested it, and `/365` returned a different (false) result than ` / 365.25` indicated here. – Cyril N. Dec 21 '12 at 13:31
  • Yeah but shouldn't I cut the result with a function like floor? I could get a non-integer age. – Ramy Al Zuhouri Dec 21 '12 at 13:45
  • 1
    I'm not sure to understand here. floor returns a BigInt, not a floating value. datediff returns an int, divised by a float, but rounded to the lower int. – Cyril N. Dec 21 '12 at 13:50
  • This is still not quite right. Leap years are not every 4 years, they're every 4 years, except every 100, except every 1000. 1900 was not a leap year. 2000 was. This will ***happen to work*** because 2000 was a leap year and most birthday calculations will span 2000, but it be off by a day when spanning 1900 or 2100. `select floor(datediff("2117-03-19", "2075-03-19") / 365.25)` says 41, it should be 42. You can't divide the number of days to get years, even using 365.242222 won't work quite right. You have to do the math. – Schwern Jan 30 '17 at 21:00
1

Why not use MySQL's FLOOR() function on the output from your second approach? Any fractions will be dropped, giving you the result you want.

Harper Shelby
  • 16,475
  • 2
  • 44
  • 51
1

I have not enough reputation to add comment to an answer by Rat-a-tat-a-tat Ratatouille to improve his code. Here is the better SQL-query:

SELECT IFNULL(TIMESTAMPDIFF(YEAR, birthdate, CURDATE()), YEAR(CURDATE()) - YEAR(birthdate)) AS age

This is better because sometimes "birthdate" may contain only year of birth, while day and month is 0. If TIMESTAMPDIFF() returns NULL, we can find rough age by subtracting the current year from the year of birth.

0

You can use this to get integer value.

select id, CAST(datediff(curdate(),birth_date) / 365 as int)
from student

If you want to read about CONVERT() and CAST() here is the link.

Amit
  • 21,570
  • 27
  • 74
  • 94
0

I'd suggest this:

DATE_FORMAT(NOW(),"%Y")
   -DATE_FORMAT(BirthDate,'%Y')
   -(
     IF(
      DATE_FORMAT(NOW(),"%m-%d") < DATE_FORMAT(BrthDate,'%m-%d'),
      1,
      0
     )
    ) as Age

This should work with leap-years very well ;-)

0

This works, even taking in account leap years!

select floor((cast(date_format('2016-02-29','%Y%m%d') as int) - cast(date_format('1966-03-01','%Y%m%d') as int)/10000);

Just be sure to keep the floor() as the decimal is not needed

Jarod Moser
  • 7,022
  • 2
  • 24
  • 52