views:

631

answers:

6

Hi

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?

My data looks as follows

ID    Name   DOB
1     John   1992-01-09 00:00:00
2     Sally  1959-05-20 00:00:00

I would like to see:

ID    Name   AGE  DOB
1     John   17   1992-01-09 00:00:00
2     Sally  50   1959-05-20 00:00:00

Many thanks!

A: 
SELECT ID,
Name,
DATEDIFF(yy,CONVERT(DATETIME, DOB),GETDATE()) AS AGE,
DOB
FROM MyTable
flayto
You want getdate as the second argument not the first otherwise you get negative number results, and datediff rounds, so select datediff(yy, '20081231', getdate()) will report an age of 1, but they would only be 10 months old.
Andrew
You are correct - my bad. Thanks.
flayto
A: 

You need to consider the way the datediff command rounds.

SELECT CASE WHEN dateadd(year, datediff (year, DOB, getdate()), DOB) > getdate()
            THEN datediff(year, DOB, getdate()) - 1
            ELSE datediff(year, DOB, getdate())
       END as Age
FROM <table>

Which I adapted from here

Ed Harper
Ed, Whats d1 and d2 in this?
Andrew
@Andrew - Corrected - I missed one of the substitutions
Ed Harper
A: 

I have used this query in our production code for nearly 10 years:

SELECT FLOOR((CAST (GetDate() AS INTEGER) - CAST(Date_of_birth AS INTEGER)) / 365.25) AS Age
_J_
It's not bad, but is not 100%, 2007/10/16 will report an age of 2 on 2009/10/15
Andrew
It doesn't on mine, it returns 1 which is the correct answer.
_J_
returns 1 for me too
KM
Weird, I get 2, Today cast as int is 40100, 2007/10/16 is 36939, the difference is 731, divided by 365.25 gives 2.001368 which floors to 2, but the birthday is 1 day away so should give the 1 you are getting. I'm running it on 2005 but shouldn't make a difference.
Andrew
Here's something interesting: If I CAST (GetDate() AS INT), I get 40100 as you do. But if I CAST ({d '2009-10-15'} AS INT (which is today's date), I get 40099. Hence the day's difference.So re-running my query with GetDate() returns 2, but re-running it with the CAST ({d '2009-10-15'} returns 1.I wonder if it is somethig to do with the time element? SELECT {d '2009-10-15'} returns '15/10/2009'butSELECT GetDate() returns 15/10/2009 4:57:57 pm
_J_
Doh, we're missing the obvious, it's after mid-day, getdate returns an int so will be rounding up of course. I copy pasted your answer and ran it, so automatically used getdate, not the literal.
Andrew
+2  A: 

This is a knotty little problem because you have to take into account whether the burthday has occured this year to the day. I would prefer using datepart(dy,..) to get the day count but it fails on a leap year scenario and misreports the age by 1 day.

declare @DOB datetime
set @DOB = convert(datetime,'2007/10/15')

Select DateDiff(yy,@DOB,getdate()) 
- CASE WHEN datepart  (mm,@DOB) <= DatePart(mm,getdate()) and datepart(dd,@DOB) <= datepart(dd,getdate())
  THEN 0 
  ELSE 1
  END AS Age

Used the datediff, but then modify it back down a year if the birthday has not yet passed, or leave it as it is if you've already had your cards and presents :)

I 'think' that holds, but it's an annoying little problem.

Andrew
Thanks Andrew, that solution worked for me, but I've altered it slightly as KMs' solution is smaller
James.Elsey
+3  A: 

try this:

DECLARE @dob  datetime
SET @dob='1992-01-09 00:00:00'

SELECT DATEDIFF(hour,@dob,GETDATE())/8766.0 AS AgeYearsDecimal
    ,CONVERT(int,ROUND(DATEDIFF(hour,@dob,GETDATE())/8766.0,0)) AS AgeYearsIntRound
    ,DATEDIFF(hour,@dob,GETDATE())/8766 AS AgeYearsIntTrunc

OUTPUT:

AgeYearsDecimal                         AgeYearsIntRound AgeYearsIntTrunc
--------------------------------------- ---------------- ----------------
17.767054                               18               17

(1 row(s) affected)
KM
Thanks KM, I'm using the truncated option, works a treat!
James.Elsey
There were issues importing the varchar as datetime originally (hence DOB is stored as a varchar), but you can use this method? How does that make sense? Don't you get the same 'issues' here?
Kirk Broadhurst
@Kirk Broadhurst, possibly they loaded them into this table using varchar, and then did a second pass fixing them up. It would be better to load them into a work table using varchar and then fix them before moving them to the actual table where they are datetime.
KM
A: 

Gotta throw this one out there.

(yyyyMMdd - yyyyMMdd) / 10000 = difference in full years

declare @as_of datetime, @bday datetime;
select @as_of = '2009/10/15', @bday = '1980/4/20'

select 
    Convert(Char(8),@as_of,112),
    Convert(Char(8),@bday,112),
    0 + Convert(Char(8),@as_of,112) - Convert(Char(8),@bday,112), 
    (0 + Convert(Char(8),@as_of,112) - Convert(Char(8),@bday,112)) / 10000

output

20091015    19800420 290595 29
dotjoe