How to calculate age in T-SQL with years, months, and days

Here is some T-SQL that gives you the number of years, months, and days since the day specified in @date. It takes into account the fact that DATEDIFF() computes the difference without considering what month or day it is (so the month diff between 8/31 and 9/1 is 1 month) and handles that with a case statement that decrements the result where appropriate.

DECLARE @date datetime, @tmpdate datetime, @years int, @months int, @days int
SELECT @date = '2/29/04'

SELECT @tmpdate = @date

SELECT @years = DATEDIFF(yy, @tmpdate, GETDATE()) - CASE WHEN (MONTH(@date) > MONTH(GETDATE())) OR (MONTH(@date) = MONTH(GETDATE()) AND DAY(@date) > DAY(GETDATE())) THEN 1 ELSE 0 END
SELECT @tmpdate = DATEADD(yy, @years, @tmpdate)
SELECT @months = DATEDIFF(m, @tmpdate, GETDATE()) - CASE WHEN DAY(@date) > DAY(GETDATE()) THEN 1 ELSE 0 END
SELECT @tmpdate = DATEADD(m, @months, @tmpdate)
SELECT @days = DATEDIFF(d, @tmpdate, GETDATE())

SELECT @years, @months, @days

Try this...

SELECT CASE WHEN
 (DATEADD(year,DATEDIFF(year, @datestart  ,@dateend) , @datestart) > @dateend)
THEN DATEDIFF(year, @datestart  ,@dateend) -1
ELSE DATEDIFF(year, @datestart  ,@dateend)
END

Basically the "DateDiff( year...", gives you the age the person will turn this year, so i have just add a case statement to say, if they have not had a birthday yet this year, then subtract 1 year, else return the value.


Simple way to get age as text is as below:

Select cast((DATEDIFF(m, date_of_birth, GETDATE())/12) as varchar) + ' Y & ' + 
       cast((DATEDIFF(m, date_of_birth, GETDATE())%12) as varchar) + ' M' as Age

Results Format will be:

**63 Y & 2 M**

Implemented by arithmetic with ISO formatted date.

declare @now date,@dob date, @now_i int,@dob_i int, @days_in_birth_month int
declare @years int, @months int, @days int
set @now = '2013-02-28' 
set @dob = '2012-02-29' -- Date of Birth

set @now_i = convert(varchar(8),@now,112) -- iso formatted: 20130228
set @dob_i = convert(varchar(8),@dob,112) -- iso formatted: 20120229
set @years = ( @now_i - @dob_i)/10000
-- (20130228 - 20120229)/10000 = 0 years

set @months =(1200 + (month(@now)- month(@dob))*100 + day(@now) - day(@dob))/100 %12
-- (1200 + 0228 - 0229)/100 % 12 = 11 months

set @days_in_birth_month = day(dateadd(d,-1,left(convert(varchar(8),dateadd(m,1,@dob),112),6)+'01'))
set @days = (sign(day(@now) - day(@dob))+1)/2 * (day(@now) - day(@dob))
          + (sign(day(@dob) - day(@now))+1)/2 * (@days_in_birth_month - day(@dob) + day(@now))
-- ( (-1+1)/2*(28 - 29) + (1+1)/2*(29 - 29 + 28))
-- Explain: if the days of now is bigger than the days of birth, then diff the two days
--          else add the days of now and the distance from the date of birth to the end of the birth month 
select @years,@months,@days -- 0, 11, 28 

Test Cases

The approach of days is different from the accepted answer, the differences shown in the comments below:

       dob        now  years  months  days 
2012-02-29 2013-02-28      0      11    28  --Days will be 30 if calculated by the approach in accepted answer. 
2012-02-29 2016-02-28      3      11    28  --Days will be 31 if calculated by the approach in accepted answer, since the day of birth will be changed to 28 from 29 after dateadd by years. 
2012-02-29 2016-03-31      4       1     2
2012-01-30 2016-02-29      4       0    30
2012-01-30 2016-03-01      4       1     2  --Days will be 1 if calculated by the approach in accepted answer, since the day of birth will be changed to 30 from 29 after dateadd by years.
2011-12-30 2016-02-29      4       1    30

An short version of Days by case statement:

set @days = CASE WHEN day(@now) >= day(@dob) THEN day(@now) - day(@dob)
                 ELSE @days_in_birth_month - day(@dob) + day(@now) END

If you want the age of years and months only, it could be simpler

set @years = ( @now_i/100 - @dob_i/100)/100
set @months =(12 + month(@now) - month(@dob))%12 
select @years,@months -- 1, 0

NOTE: A very useful link of SQL Server Date Formats