Domanda

I have two computed columns (MonthsInService and YearsInService) with the following expressions.

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

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

Now if for example DateEngaged = 2012-April-09 and getdate() is 2013-April-08, MonthsInService returns 12 and YearsInService is 1.

My application requires that YearsInService be Zero since there is still one day to go before the employees first Anniversary.

Am not even sure how to best handle the MonthsInService column since months have varying number of days.

È stato utile?

Soluzione 2

Via using day you can reach the result:

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

Output:

12  0  

or use function for maximum precision:

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

For months calculation you can refer here: Calculating number of full months between two dates in SQL

Altri suggerimenti

Unfortunately, DATEDIFF computes the number of transitions of the element, rather than the usual, human intuition of the difference between two dates (e.g. DATEDIFF(year,'20121231','20130101') is 1, even though not many people would say that there's a difference of a year).

The solution I'd use is a bit repetitive, but doesn't need a separate function, and always gets e.g. leap years correct:

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

Produces:

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

It works by asking "If we take the naive answer produced by DATEDIFF, does it given an answer that's too high by 1?" - and if so, we just subtract one from the answer it gives. DATEDIFF should only ever be over by 1.

Try this query :

DATEDIFF(DAY, CONVERT(date, dtmDOB),                         
  CONVERT(date, GETDATE()))*(12.0/365.25)),1))                      
  AS TotalMonths,         
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top