Reputation: 411
I need some help with SQL Server 2012 trying to calculate an Aging Years Field for a report.
Basically, I have two fields StartDateTime and EndDateTime and here is some sample data below:
StartDateTime EndDateTime
2006-10-10 16:08:13.523 2008-04-11 00:00:00.000
2016-05-11 13:03:48.093 2016-06-16 00:00:00.000
2016-08-01 12:44:42.990 2016-08-01 00:00:00.000
2016-05-20 17:33:27.957 2016-05-25 00:00:00.000
2006-10-19 21:41:41.350 NULL
I am currently trying to make an AgingYears field to calculate the Aging Years between both fields (as exact as possible.) And when EndDateTime is NULL, it should calculate the difference between GETDATE() and StartDateTime. When StartDateTime is greater than EndDateTime (which I don't know why I have some data like this, but I do), then it should just return back 0.
I tried doing some code based off websites I found related, but it's not helping me much and this is where I'm stuck at:
DATEDIFF(YY, StartDateTime, EndDateTime) -
CASE
WHEN DATEADD(YY,DATEDIFF(YY,StartDateTime, EndDateTime),StartDateTime)
> A.[END_DTTM]
THEN DATEDIFF(YY, StartDateTime, EndDateTime)- 1
ELSE DATEDIFF(YY, StartDateTime, EndDateTime)
END AS AgeInYears,
Any help with my code would be greatly appreciated.
Upvotes: 3
Views: 327
Reputation: 967
I think it should be like this:
SELECT StartDate
, EndDate
, CASE
WHEN DATEDIFF(YY, StartDate, ISNULL(EndDate, GETDATE())) < 0
THEN 0
ELSE DATEDIFF(YY, StartDate, ISNULL(EndDate, GETDATE()))
END AS AgingYears
FROM YourTableName
Upvotes: 1
Reputation: 17915
Be careful about leap years. How do you want February 29 to February 28 to be treated?
case
when year(coalesce(EndDateTime, getdate()) > year(StartDateTime)
then
datediff(year, StartDateTime, coalesce(EndDateTime, getdate())) -
case
when
EndDateTime is not null and
datepart(month, EndDateTime) < datepart(month, StartDateTime)
or datepart(month, EndDateTime) = datepart(month, StartDateTime)
and datepart(day, EndDateTime) < datepart(day, StartDateTime)
then 1
when
EndDateTime is null and
datepart(month, getdate()) < datepart(month, StartDateTime)
or datepart(month, getdate()) = datepart(month, StartDateTime)
and datepart(day, getdate()) < datepart(day, StartDateTime)
then 1
else 0
end
else 0
end
I split the EndDateTime
and getdate()
cases mostly because it looked better without the scroll bar on the long lines.
Here's one way to tweak that logic and catch the leap day condition treating it as a full year even though the dates don't strictly coincide. You'd need to duplicate this expression (substitute getdate() for
EndDateTimeeverywhere except the
is null` test) in both branches if you keep the "split" logic the way I wrote it above.
when
EndDateTime is not null and
datepart(month, EndDateTime) < datepart(month, StartDateTime)
or datepart(month, EndDateTime) = datepart(month, StartDateTime)
and datepart(day, EndDateTime) < datepart(day, StartDateTime)
and not -- here's one way to catch the leap day condition
(
-- adding one day this way is deprecated and only works with datetime
and datepart(month, StartDateTime + 1) > datepart(month, StartDateTime)
and datepart(month, EndDateTime + 1) > datepart(month, EndDateTime)
)
Btw, once you understand that approach there's a way to condense the same logic using arithmetic on numbers in yyyymmdd format.
(
cast(convert(varchar(8), @EndDateTime, 120) as int) -
cast(convert(varchar(8), @StartDateTime, 120) as int)
) / 10000
All the complicated logic above is simply borrowing from the years place in the subtraction. It's pretty much the same thing.
Upvotes: 2