How to calculate age (in years) based on Date of Birth and getDate()
我有一张表,上面列出了人们的出生日期(目前是女大主教(25))。
我怎样才能把它转换成一个日期,然后计算它们的年龄(以年为单位)?
我的数据如下
1 2 3 | ID Name DOB 1 John 1992-01-09 00:00:00 2 Sally 1959-05-20 00:00:00 |
我想看看:
1 2 3 | ID Name AGE DOB 1 John 17 1992-01-09 00:00:00 2 Sally 50 1959-05-20 00:00:00 |
闰年/天数和以下方法存在问题,请参阅以下更新:
0更新以下是一些更准确的方法:
整年最佳方法
1 2 3 4 5 6 7 8 9 10 | 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 |
您可以将上面的
十进制年份最佳方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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)将日期转换为数字,则可以使用如下计算方法…
(YYYYMMDD-YYMMDD)/10000=全年差异
1 2 3 4 5 6 7 8 | 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 |
输出
1 | 20091015 19800420 290595 29 |
我在我们的生产代码中使用此查询已近10年:
2上述许多解决方案都是错误的日期diff(yy,@dob,@passedate)不会考虑这两个日期的月和日。另外,只有在订购正确的情况下,才能对省道部件进行比较。
下面的代码可以工作,非常简单:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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 |
您需要考虑datediff命令的循环方式。
1 2 3 4 5 | 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> |
我从这里改编的
编辑:此答案不正确。我把它放在这里是为了警告任何想使用
如果像我一样,你不想除以分数日或风险舍入/闰年错误,我在https://stackoverflow.com/a/1572257/489865上面的帖子中为@bacon bits的评论鼓掌,他说:
0然后他提出:
1 2 3 | 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 |
这里有几个建议涉及到比较月份和日期(有些人认为是错误的,未能正确地考虑到
1 2 | DATEDIFF(year, @date, GETDATE()) - CASE WHEN DATEPART(dayofyear, @date) > DATEPART(dayofyear, GETDATE()) THEN 1 ELSE 0 END |
[注:在SQL BOL/msdn中没有任何地方是实际记录的
编辑:为什么
因为没有一个简单的答案总是能给出正确的年龄,所以我想到的就是这个。
1 2 3 4 | 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 |
这将获取出生日期和当前日期之间的年份差异。如果生日还没有过,那么它减去一年。
始终准确-无论闰年或离出生日期有多近。
最棒的是-没有功能。
我相信这和其他贴在这里的一样……但该解决方案适用于闰年示例02/29/1976至03/01/2011,并且也适用于第一年的案例。比如2011年4月7日到2012年3月7日,上一篇关于闰年解决方案的文章在第一年的用例中不起作用。
1 | SELECT FLOOR(DATEDIFF(DAY, @date1 , @date2) / 365.25) |
在这里找到的。
Just check whether the below answer is feasible.
1 2 3 4 5 6 7 8 9 10 11 | 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 ) |
如何:
1 2 3 | DECLARE @DOB datetime SET @DOB='19851125' SELECT Datepart(yy,convert(date,GETDATE())-@DOB)-1900 |
难道这就不能避免所有的舍入、截断和设置问题吗?
1 2 3 4 5 | SELECT ID, Name, DATEDIFF(yy,CONVERT(DATETIME, DOB),GETDATE()) AS AGE, DOB FROM MyTable |
1 2 3 4 5 6 7 | 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/
我做了很多思考和研究,我有3个解决方案
- 正确计算年龄
- 短(大部分)
- 基本上是可以理解的。
以下是测试值:
2解决方案1:我在一个JS库中发现了这种方法。这是我最喜欢的。
1 2 | DATEDIFF(YY, @DOB, @NOW) - CASE WHEN DATEADD(YY, DATEDIFF(YY, @DOB, @NOW), @DOB) > @NOW THEN 1 ELSE 0 END |
它实际上是在dob中加上年份差异,如果大于当前日期,则减去一年。简单的权利?唯一的一点是,年的差异在这里是重复的。
但是如果您不需要直接使用它,您可以这样编写它:
1 2 3 | DECLARE @AGE INT = DATEDIFF(YY, @DOB, @NOW) IF DATEADD(YY, @AGE, @DOB) > @NOW SET @AGE = @AGE - 1 |
解决方案2:我最初从@bacon位复制的这个。这是最容易理解的,但有点长。
1 2 3 4 | 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 |
它基本上和人类一样计算年龄。
解决方案3:我的朋友将其重构为:
1 2 | DATEDIFF(YY, @DOB, @NOW) - CEILING(0.5 * SIGN((MONTH(@DOB) - MONTH(@NOW)) * 50 + DAY(@DOB) - DAY(@NOW))) |
这是最短的,但最难理解。
1 2 3 4 5 6 7 8 9 | 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 |
尝试此解决方案:
1 2 3 4 5 6 7 8 9 | 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 |
EdHarper的解决方案是我发现的最简单的方法,当两个日期的月和日相距不到1天时,它不会返回错误的答案。我做了一个小小的修改来处理消极的年龄。
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 |
试试这个
1 2 3 4 5 6 7 8 9 10 11 12 | 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' |
这将正确处理生日和舍入问题:
1 2 3 4 | DECLARE @dob datetime SET @dob='1992-01-09 00:00:00' SELECT DATEDIFF(YEAR, '0:0', getdate()-@dob) |
这个怎么样?
1 2 3 | 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 |
1 | select floor((datediff(day,0,@today) - datediff(day,0,@birthdate)) / 365.2425) as age |
这里有很多365.25个答案。记住闰年是如何定义的:
- 每四年
- 除非每100年
- 除了每400年
- 除非每100年
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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 |
标记为"正确"的答案更接近准确,但在以下情况中失败-出生年份为闰年,日期在2月之后
1 2 3 4 | declare @ReportStartDate datetime = CONVERT(datetime, '1/1/2014'), @DateofBirth datetime = CONVERT(datetime, '2/29/1948') FLOOR(DATEDIFF(HOUR,@DateofBirth,@ReportStartDate )/8766) |
或
1 | FLOOR(DATEDIFF(HOUR,@DateofBirth,@ReportStartDate )/8765.82) -- Divisor is more accurate than 8766 |
--下面的解决方案给了我更准确的结果。
1 | FLOOR(DATEDIFF(YEAR,@DateofBirth,@ReportStartDate) - (CASE WHEN DATEADD(YY,DATEDIFF(YEAR,@DateofBirth,@ReportStartDate),@DateofBirth) > @ReportStartDate THEN 1 ELSE 0 END )) |
它几乎适用于所有场景,考虑到闰年、日期为2月29日等。
如果这个公式有漏洞,请纠正我。
下面是我如何计算给定出生日期和当前日期的年龄。
1 2 3 4 5 6 | 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 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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 |
在尝试了许多方法之后,使用现代的MS SQL格式函数(而不是转换为样式112)可以100%地工作。两者都可以,但这是最少的代码。
有人能找到一个不起作用的日期组合吗?我不认为有一个:)
1 2 3 4 5 6 7 | --Set parameters, or choose from table.column instead: DECLARE @DOB DATE = '2000/02/29' -- If @DOB is a leap day... ,@ToDate DATE = '2018/03/01' --...there birthday in this calculation will be --0+ part tells SQL to calc the char(8) as numbers: SELECT [Age] = (0+ FORMAT(@ToDate,'yyyyMMdd') - FORMAT(@DOB,'yyyyMMdd') ) /10000 |
如果一个解决方案只有日期函数,而不是数学,不用担心闰年
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | CREATE FUNCTION dbo.getAge(@dt datetime) RETURNS int AS BEGIN RETURN DATEDIFF(yy, @dt, getdate()) - CASE WHEN MONTH(@dt) > MONTH(GETDATE()) OR (MONTH(@dt) = MONTH(GETDATE()) AND DAY(@dt) > DAY(GETDATE())) THEN 1 ELSE 0 END END |
1 2 3 4 5 6 7 8 9 10 11 | 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 |
我们在这里使用了类似的方法,然后取平均年龄:
1 | ROUND(avg(CONVERT(int,DATEDIFF(hour,DOB,GETDATE())/8766.0)),0) AS AverageAge |
注意,圆是在外面而不是在里面。这将使平均值更精确,我们只进行一次取整。速度也更快。
1 2 3 4 | 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 |
1 | SELECT CAST(DATEDIFF(dy, @DOB, GETDATE()+1)/365.25 AS int) |
您应按以下方式计算年数:
1 | select cast(datediff(DAY, '2000-03-01 10:00:01', '2013-03-01 10:00:00') / (365.23076923074) as int) as 'Age' |
很容易…
1 2 3 | 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 |
你应该使用从表名称中选择楼层(datediff(curdate(),date(dob))/365.25);这里curdate()使用当前日期,您可以用"yyyy-mm-dd"格式给出自己的日期。日期(DOB)从日期时间格式的列中提取年-月-日-年这里,dob是您的列名(但是您应该更改table以将数据类型修改为datetime,在您的情况下是nvarchar)注释-此查询用于mysql这一年的返校年龄
1 2 | DECLARE @yourBirthDate DATETIME = '1987-05-25' SELECT YEAR(DATEADD(DAY, DATEDIFF(DAY, @yourBirthDate, GETDATE()), CAST('0001-01-01' AS DATETIME2))) - 1 |