在SQL Server中使用DATEDIFF的最准确方法是什么?

时间:2013-04-08 10:47:35

标签: sql-server tsql sql-server-2005 datediff

我有两个带有以下表达式的计算列(MonthsInService和YearsInService)。

MonthsInService = (datediff(month,[DateEngaged],getdate()))

YearsInService = (datediff(month,[DateEngaged],getdate())/(12))

现在,如果例如DateEngaged = 2012-April-09和getdate()是2013年4月8日,则MonthsInService返回12并且YearsInService为1.

我的申请要求YearsInService为零,因为在员工成立一周年之前还有一天要去。

我甚至不确定如何最好地处理MonthsInService列,因为几个月有不同的天数。

2 个答案:

答案 0 :(得分:5)

不幸的是,DATEDIFF计算元素的过渡的数量,而不是两个日期之间差异的通常的人类直觉(例如DATEDIFF(year,'20121231','20130101')是1,甚至虽然没有多少人会说有一年的差异。)

我使用的解决方案有点重复,但不需要单独的功能,并且总是得到例如闰年正确:

declare @T table (
    DateEngaged datetime not null,
    MonthsInService as CASE
        WHEN DATEADD(month,DATEDIFF(month,DateEngaged,GETDATE()),DateEngaged) > GETDATE()
            THEN DATEDIFF(month,DateEngaged,GETDATE()) - 1
            ELSE DATEDIFF(month,DateEngaged,GETDATE())
        END,
    YearsInService as CASE
        WHEN DATEADD(year,DATEDIFF(year,DateEngaged,GETDATE()),DateEngaged) > GETDATE()
            THEN DATEDIFF(year,DateEngaged,GETDATE()) - 1
            ELSE DATEDIFF(year,DateEngaged,GETDATE())
        END
)

insert into @T (DateEngaged) values ('20120409'),('20120408')

select * from @T

产地:

DateEngaged             MonthsInService YearsInService
----------------------- --------------- --------------
2012-04-09 00:00:00.000 11              0
2012-04-08 00:00:00.000 12              1

它的工作原理是“如果我们接受DATEDIFF产生的天真答案,那么答案是否过高了1?” - 如果是这样,我们只从它给出的答案中减去一个。 DATEDIFF应该只能超过1。

答案 1 :(得分:1)

通过使用day,您可以达到结果:

select 
datediff(month,'2012-April-09','2013-April-08') MonthsInService
,datediff(day,'2012-April-09','2013-April-08')/365 YearsInService

输出

12  0  

或使用函数获得最大精度:

CREATE FUNCTION [dbo].[getFullYears] 
(
    @dateX datetime,
    @dateY datetime
)  
RETURNS int
AS  
BEGIN 
    DECLARE @y int
    SET @y =DATEDIFF(year,@dateX,@dateY)
    IF (@dateY < DATEADD(year, @y, @dateX)) SET @y = @y -1
    RETURN @y
END

select dbo.getFullYears('2012-April-09','2013-April-09') --1
select dbo.getFullYears('2012-April-09','2013-April-08') --0

对于月份计算,您可以在此处参考:Calculating number of full months between two dates in SQL