I have a table listing people along with their date of birth (currently a nvarchar(25))
How can I convert that to a date, and then calculate their age in years?
EDIT: THIS ANSWER IS INCORRECT. I leave it in here as a warning to anyone tempted to use dayofyear
, with a further edit at the end.
If, like me, you do not want to divide by fractional days or risk rounding/leap year errors, I applaud @Bacon Bits comment in a post above https://stackoverflow.com/a/1572257/489865 where he says:
If we're talking about human ages, you should calculate it the way humans calculate age. It has nothing to do with how fast the earth moves and everything to do with the calendar. Every time the same month and day elapses as the date of birth, you increment age by 1. This means the following is the most accurate because it mirrors what humans mean when they say "age".
He then offers:
DATEDIFF(yy, @date, GETDATE()) -
CASE WHEN (MONTH(@date) > MONTH(GETDATE())) OR (MONTH(@date) = MONTH(GETDATE()) AND DAY(@date) > DAY(GETDATE()))
THEN 1 ELSE 0 END
There are several suggestions here involving comparing the month & day (and some get it wrong, failing to allow for the OR
as correctly here!). But nobody has offered dayofyear
, which seems so simple and much shorter. I offer:
DATEDIFF(year, @date, GETDATE()) -
CASE WHEN DATEPART(dayofyear, @date) > DATEPART(dayofyear, GETDATE()) THEN 1 ELSE 0 END
[Note: Nowhere in SQL BOL/MSDN is what DATEPART(dayofyear, ...)
returns actually documented! I understand it to be a number in the range 1--366; most importantly, it does not change by locale as per DATEPART(weekday, ...)
& SET DATEFIRST
.]
EDIT: Why dayofyear
goes wrong: As user @AeroX has commented, if the birth/start date is after February in a non leap year, the age is incremented one day early when the current/end date is a leap year, e.g. '2015-05-26'
, '2016-05-25'
gives an age of 1 when it should still be 0. Comparing the dayofyear
in different years is clearly dangerous. So using MONTH()
and DAY()
is necessary after all.