如何根据出生date和getDate()计算年龄(以年为单位)

我有一张表列出了他们的出生date(目前是nvarchar(25))

我怎样才能把它转换成一个date,然后计算他们的年龄?

我的数据如下所示

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

我想看看:

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

有闰年/天的问题和以下方法,请参阅下面的更新:

尝试这个:

 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) 

这里更新一些更准确的方法:

年龄最好的方法在INT

 DECLARE @Now datetime, @Dob datetime SELECT @Now='1990-05-05', @Dob='1980-05-05' --results in 10 --SELECT @Now='1990-05-04', @Dob='1980-05-05' --results in 9 --SELECT @Now='1989-05-06', @Dob='1980-05-05' --results in 9 --SELECT @Now='1990-05-06', @Dob='1980-05-05' --results in 10 --SELECT @Now='1990-12-06', @Dob='1980-05-05' --results in 10 --SELECT @Now='1991-05-04', @Dob='1980-05-05' --results in 10 SELECT (CONVERT(int,CONVERT(char(8),@Now,112))-CONVERT(char(8),@Dob,112))/10000 AS AgeIntYears 

你可以改变1000010000.0以上的小数,但不会像下面的方法那么精确。

十进制年的最佳方法

 DECLARE @Now datetime, @Dob datetime SELECT @Now='1990-05-05', @Dob='1980-05-05' --results in 10.000000000000 --SELECT @Now='1990-05-04', @Dob='1980-05-05' --results in 9.997260273973 --SELECT @Now='1989-05-06', @Dob='1980-05-05' --results in 9.002739726027 --SELECT @Now='1990-05-06', @Dob='1980-05-05' --results in 10.002739726027 --SELECT @Now='1990-12-06', @Dob='1980-05-05' --results in 10.589041095890 --SELECT @Now='1991-05-04', @Dob='1980-05-05' --results in 10.997260273973 SELECT 1.0* DateDiff(yy,@Dob,@Now) +CASE WHEN @Now >= DATEFROMPARTS(DATEPART(yyyy,@Now),DATEPART(m,@Dob),DATEPART(d,@Dob)) THEN --birthday has happened for the @now year, so add some portion onto the year difference ( 1.0 --force automatic conversions from int to decimal * DATEDIFF(day,DATEFROMPARTS(DATEPART(yyyy,@Now),DATEPART(m,@Dob),DATEPART(d,@Dob)),@Now) --number of days difference between the @Now year birthday and the @Now day / DATEDIFF(day,DATEFROMPARTS(DATEPART(yyyy,@Now),1,1),DATEFROMPARTS(DATEPART(yyyy,@Now)+1,1,1)) --number of days in the @Now year ) ELSE --birthday has not been reached for the last year, so remove some portion of the year difference -1 --remove this fractional difference onto the age * ( -1.0 --force automatic conversions from int to decimal * DATEDIFF(day,DATEFROMPARTS(DATEPART(yyyy,@Now),DATEPART(m,@Dob),DATEPART(d,@Dob)),@Now) --number of days difference between the @Now year birthday and the @Now day / DATEDIFF(day,DATEFROMPARTS(DATEPART(yyyy,@Now),1,1),DATEFROMPARTS(DATEPART(yyyy,@Now)+1,1,1)) --number of days in the @Now year ) END AS AgeYearsDecimal 

把它扔到那里 如果您使用112样式(yyyymmdd) 将date转换为数字,则可以使用像这样的计算…

(yyyyMMdd – yyyyMMdd)/ 10000 =全年的差额

 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 

产量

 20091015 19800420 290595 29 

我在生产代码中使用了这个查询近10年:

 SELECT FLOOR((CAST (GetDate() AS INTEGER) - CAST(Date_of_birth AS INTEGER)) / 365.25) AS Age 

所以很多上面的解决scheme是错误的DateDiff(YY,@ DOB,@PassedDate)不会考虑这两个date的月份和date。 也可以拿飞镖部分和比较只有正确的命令。

以下代码正常工作,非常简单:

 create function [dbo].[AgeAtDate]( @DOB datetime, @PassedDate datetime ) returns int with SCHEMABINDING as begin declare @iMonthDayDob int declare @iMonthDayPassedDate int select @iMonthDayDob = CAST(datepart (mm,@DOB) * 100 + datepart (dd,@DOB) AS int) select @iMonthDayPassedDate = CAST(datepart (mm,@PassedDate) * 100 + datepart (dd,@PassedDate) AS int) return DateDiff(yy,@DOB, @PassedDate) - CASE WHEN @iMonthDayDob <= @iMonthDayPassedDate THEN 0 ELSE 1 END End 

您需要考虑过期的指令的方式。

 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> 

我从这里改编的

编辑:这个答案是不正确的。 我把它留在这里作为一个警告,任何人试图使用dayofyear ,并在最后进一步编辑。


如果像我一样,你不想以分数天或风险舍入/闰年错误来划分,我赞扬@Bacon位评论在上面的post上,他说:

如果我们谈论人类的年龄,那么应该按照人类计算年龄的方式来计算它。 它与地球运动的速度以及与日历有关的一切无关。 每当同一个月份和一天的date与出生date相同的时候,年龄就会增加1.这意味着以下是最准确的,因为它反映了人们说“年龄”时的意思。

然后他提供:

 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 

这里有几个build议,比较一下这个月和一天(有些人错了,在这里没有考虑到OR )。 但是没有人提供dayofyear这么简单和短得多的dayofyear 。 我提供:

 DATEDIFF(year, @date, GETDATE()) - CASE WHEN DATEPART(dayofyear, @date) > DATEPART(dayofyear, GETDATE()) THEN 1 ELSE 0 END 

[注意:SQL中无处不在BOL / MSDN是DATEPART(dayofyear, ...)返回的实际logging! 我理解它是1-366范围内的数字; 最重要的是,它不会按照DATEPART(weekday, ...)DATEPART(weekday, ...)SET DATEFIRST语言环境更改。]


编辑: 为什么dayofyear出错 :正如用户@AeroX已经评论,如果出生/开始date是在非闰年二月之后,年龄提前一天当当前/结束date是闰年,例如'2015-05-26''2016-05-25'的年龄为1时,应该仍然是0.比较不同年份的年份显然是危险的。 所以使用MONTH()DAY()毕竟是必须的。

既然没有一个简单的答案总能给出正确的年龄,那么我就是这样想的。

 SELECT DATEDIFF(YY, DateOfBirth, GETDATE()) - CASE WHEN RIGHT(CONVERT(VARCHAR(6), GETDATE(), 12), 4) >= RIGHT(CONVERT(VARCHAR(6), DateOfBirth, 12), 4) THEN 0 ELSE 1 END AS AGE 

这会得到出生date和当前date之间的年份差异。 然后,如果出生date还没有过去,它就会减去一年。

无论闰年还是与出生date有多接近,都是准确无误的。

最棒的是 – 没有function。

关于什么:

 DECLARE @DOB datetime SET @DOB='19851125' SELECT Datepart(yy,convert(date,GETDATE())-@DOB)-1900 

难道这不会避免所有那些四舍五入,截断和困扰的问题吗?

只要检查下面的答案是否可行。

 DECLARE @BirthDate DATE = '09/06/1979' SELECT ( YEAR(GETDATE()) - YEAR(@BirthDate) - CASE WHEN (MONTH(GETDATE()) * 100) + DATEPART(dd, GETDATE()) > (MONTH(@BirthDate) * 100) + DATEPART(dd, @BirthDate) THEN 1 ELSE 0 END ) 
 DECLARE @DOB datetime set @DOB ='11/25/1985' select floor( ( cast(convert(varchar(8),getdate(),112) as int)- cast(convert(varchar(8),@DOB,112) as int) ) / 10000 ) 

来源: http : //beginsql.wordpress.com/2012/04/26/how-to-calculate-age-in-sql-server/

我相信这是类似的其他张贴在这里….但这个解决scheme工作的闰年的例子02/29/1976至03/01/2011,也为第一年的情况下工作..像07/04 / 2011年至2012年7月3日,最后一个发布有关闰年解决scheme的第一年用例不起作用。

 SELECT FLOOR(DATEDIFF(DAY, @date1 , @date2) / 365.25) 

在这里find。

 SELECT ID, Name, DATEDIFF(yy,CONVERT(DATETIME, DOB),GETDATE()) AS AGE, DOB FROM MyTable 

这个怎么样:

 SET @Age = CAST(DATEDIFF(Year, @DOB, @Stamp) as int) IF (CAST(DATEDIFF(DAY, DATEADD(Year, @Age, @DOB), @Stamp) as int) < 0) SET @Age = @Age - 1 

尝试这个

 DECLARE @date datetime, @tmpdate datetime, @years int, @months int, @days int SELECT @date = '08/16/84' 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 Convert(Varchar(Max),@years)+' Years '+ Convert(Varchar(max),@months) + ' Months '+Convert(Varchar(Max), @days)+'days' 

试试这个解决scheme

 declare @BirthDate datetime declare @ToDate datetime set @BirthDate = '1/3/1990' set @ToDate = '1/2/2008' select @BirthDate [Date of Birth], @ToDate [ToDate],(case when (DatePart(mm,@ToDate) < Datepart(mm,@BirthDate)) OR (DatePart(m,@ToDate) = Datepart(m,@BirthDate) AND DatePart(dd,@ToDate) < Datepart(dd,@BirthDate)) then (Datepart(yy, @ToDate) - Datepart(yy, @BirthDate) - 1) else (Datepart(yy, @ToDate) - Datepart(yy, @BirthDate))end) Age 

这将正确处理生日和四舍五入的问题:

 DECLARE @dob datetime SET @dob='1992-01-09 00:00:00' SELECT DATEDIFF(YEAR, '0:0', getdate()-@dob) 

埃德·哈珀的解决scheme是我find的最简单的方法,当两个date的月份和date相距不到一天或更短时间的时候,它永远不会返回错误的答案。 我做了一些小修改来处理负面的年龄。

 DECLARE @D1 AS DATETIME, @D2 AS DATETIME SET @D2 = '2012-03-01 10:00:02' SET @D1 = '2013-03-01 10:00:01' SELECT DATEDIFF(YEAR, @D1,@D2) + CASE WHEN @D1<@D2 AND DATEADD(YEAR, DATEDIFF(YEAR,@D1, @D2), @D1) > @D2 THEN - 1 WHEN @D1>@D2 AND DATEADD(YEAR, DATEDIFF(YEAR,@D1, @D2), @D1) < @D2 THEN 1 ELSE 0 END AS AGE 

标记为正确的答案接近于准确性,但在以下情况下失败 – 出生年份为闰年,而date在2月份之后

 declare @ReportStartDate datetime = CONVERT(datetime, '1/1/2014'), @DateofBirth datetime = CONVERT(datetime, '2/29/1948') FLOOR(DATEDIFF(HOUR,@DateofBirth,@ReportStartDate )/8766) 

要么

 FLOOR(DATEDIFF(HOUR,@DateofBirth,@ReportStartDate )/8765.82) -- Divisor is more accurate than 8766 

– 以下解决scheme给我更准确的结果。

 FLOOR(DATEDIFF(YEAR,@DateofBirth,@ReportStartDate) - (CASE WHEN DATEADD(YY,DATEDIFF(YEAR,@DateofBirth,@ReportStartDate),@DateofBirth) > @ReportStartDate THEN 1 ELSE 0 END )) 

它在几乎所有的情况下工作,考虑闰年,date为29二十等。

如果这个公式有漏洞,请纠正我。

 Declare @dob datetime Declare @today datetime Set @dob = '05/20/2000' set @today = getdate() select CASE WHEN dateadd(year, datediff (year, @dob, @today), @dob) > @today THEN datediff (year, @dob, @today) - 1 ELSE datediff (year, @dob, @today) END as Age 

这里是我如何计算出生date和当前date的年龄。

 select case when cast(getdate() as date) = cast(dateadd(year, (datediff(year, '1996-09-09', getdate())), '1996-09-09') as date) then dateDiff(yyyy,'1996-09-09',dateadd(year, 0, getdate())) else dateDiff(yyyy,'1996-09-09',dateadd(year, -1, getdate())) end as MemberAge go 
 CREATE function dbo.AgeAtDate( @DOB datetime, @CompareDate datetime ) returns INT as begin return CASE WHEN @DOB is null THEN null ELSE DateDiff(yy,@DOB, @CompareDate) - CASE WHEN datepart(mm,@CompareDate) > datepart(mm,@DOB) OR (datepart(mm,@CompareDate) = datepart(mm,@DOB) AND datepart(dd,@CompareDate) >= datepart(dd,@DOB)) THEN 0 ELSE 1 END END End GO 

我做了很多的思考和研究,我有3个解决scheme

  • 正确计算年龄
  • 很短(大部分)
  • (大部分)是非常可以理解的。

这里是testing值:

 DECLARE @NOW DATETIME = '2013-07-04 23:59:59' DECLARE @DOB DATETIME = '1986-07-05' 

解决scheme1:我在一个js库中find了这个方法。 这是我最喜欢的

 DATEDIFF(YY, @DOB, @NOW) - CASE WHEN DATEADD(YY, DATEDIFF(YY, @DOB, @NOW), @DOB) > @NOW THEN 1 ELSE 0 END 

这实际上是增加了与DOB的差额,如果它大于当前date,则减去一年。 简单的权利? 唯一的一点是在这个年份的差异是重复在这里。

但是如果你不需要使用它,你可以这样写:

 DECLARE @AGE INT = DATEDIFF(YY, @DOB, @NOW) IF DATEADD(YY, @AGE, @DOB) > @NOW SET @AGE = @AGE - 1 

解决scheme2:这个我最初从@ bacon-bits复制的。 这是最容易理解,但有点长。

 DATEDIFF(YY, @DOB, @NOW) - CASE WHEN MONTH(@DOB) > MONTH(@NOW) OR MONTH(@DOB) = MONTH(@NOW) AND DAY(@DOB) > DAY(@NOW) THEN 1 ELSE 0 END 

它基本上是像我们人类一样计算年龄。


解决scheme3:我的朋友把它重构成这样:

 DATEDIFF(YY, @DOB, @NOW) - CEILING(0.5 * SIGN((MONTH(@DOB) - MONTH(@NOW)) * 50 + DAY(@DOB) - DAY(@NOW))) 

这是最短的,但最难理解。 50只是一个重量,所以日子差异只在月份相同时才重要。 SIGN函数用于将所得到的任何值转换为-1,0或1. CEILING(0.5 *Math.max(0, value)相同Math.max(0, value)但在SQL中不存在。

 DECLARE @FromDate DATETIME = '1992-01-2623:59:59.000', @ToDate DATETIME = '2016-08-10 00:00:00.000', @Years INT, @Months INT, @Days INT, @tmpFromDate DATETIME SET @Years = DATEDIFF(YEAR, @FromDate, @ToDate) - (CASE WHEN DATEADD(YEAR, DATEDIFF(YEAR, @FromDate, @ToDate), @FromDate) > @ToDate THEN 1 ELSE 0 END) SET @tmpFromDate = DATEADD(YEAR, @Years , @FromDate) SET @Months = DATEDIFF(MONTH, @tmpFromDate, @ToDate) - (CASE WHEN DATEADD(MONTH,DATEDIFF(MONTH, @tmpFromDate, @ToDate), @tmpFromDate) > @ToDate THEN 1 ELSE 0 END) SET @tmpFromDate = DATEADD(MONTH, @Months , @tmpFromDate) SET @Days = DATEDIFF(DAY, @tmpFromDate, @ToDate) - (CASE WHEN DATEADD(DAY, DATEDIFF(DAY, @tmpFromDate, @ToDate), @tmpFromDate) > @ToDate THEN 1 ELSE 0 END) SELECT @FromDate FromDate, @ToDate ToDate, @Years Years, @Months Months, @Days Days 
 CASE WHEN datepart(MM, getdate()) < datepart(MM, BIRTHDATE) THEN ((datepart(YYYY, getdate()) - datepart(YYYY, BIRTH_DATE)) -1 ) ELSE CASE WHEN datepart(MM, getdate()) = datepart(MM, BIRTHDATE) THEN CASE WHEN datepart(DD, getdate()) < datepart(DD, BIRTHDATE) THEN ((datepart(YYYY, getdate()) - datepart(YYYY, BIRTHDATE)) -1 ) ELSE (datepart(YYYY, getdate()) - datepart(YYYY, BIRTHDATE)) END ELSE (datepart(YYYY, getdate()) - datepart(YYYY, BIRTHDATE)) END END 

我们使用了类似这里的东西,但是平均年龄:

 ROUND(avg(CONVERT(int,DATEDIFF(hour,DOB,GETDATE())/8766.0)),0) AS AverageAge 

注意,ROUND是在外面而不是在里面。 这将使AVG更加准确,我们只能轮换一次。 让它更快。

 select DATEDIFF(yy,@DATE,GETDATE()) - case when DATEPART(mm,GETDATE())*100+DATEPART(dd,GETDATE())>= DATEPART(mm,@DATE)*100+DATEPART(dd,@DATE) THEN 0 ELSE 1 END 
 SELECT CAST(DATEDIFF(dy, @DOB, GETDATE()+1)/365.25 AS int) 
 select datediff(day,'1991-03-16',getdate()) \\for days,get date refers today date select datediff(year,'1991-03-16',getdate()) \\for years select datediff(month,'1991-03-16',getdate()) \\for month 

你应该按照以下方法来计算年

 select cast(datediff(DAY, '2000-03-01 10:00:01', '2013-03-01 10:00:00') / (365.23076923074) as int) as 'Age' 

这很容易…

你应该使用
从table_name中selectFLOOR(DATEDIFF(CURDATE(),DATE(DOB))/ 365.25);
这里CURDATE()使用当前date,你可以给自己的date'YYYY-MM-DD'格式DATE(DOB)从你的列中提取YYYY-MM-DD年,这是在DATETIME格式在这里DOB是你的列名(但你应该alter table将数据types修改为DATETIME,在你的情况下是nvarchar)注意 – 这个查询用在mysql这个全年的返回年龄