A requirement in a recent project was to report when a resource would be fully consumed. As well as the exhaustion calendar date I was asked to show the remaining time in English-like format, something like "1 year, 3 months to go."
The built-in DATEDIFF
function
Returns the count … of the specified datepart boundaries crossed between the specified startdate and enddate.
If used as-is this could produce misleading or confusing results. For example, using an interval of YEAR would show 1999-12-31 (YYYY-MM-DD) and 2000-01-01 to be one year apart whereas common sense would say these dates are separated by only 1 day. Conversely using an interval of DAY 1999-12-31 and 2010-12-31 are separated by 4,018 days while most people would see "11 years" as a better description.
Starting from the number of days and calculating months and years from there would be prone to leap year and size-of-month errors.
I got to wondering how this could be implemented in the various SQL dialects? Example output includes:
create table TestData(
FromDate date not null,
ToDate date not null,
ExpectedResult varchar(100) not null); -- exact formatting is unimportant
insert TestData (FromDate, ToDate, ExpectedResult)
values ('1999-12-31', '1999-12-31', '0 days'),
('1999-12-31', '2000-01-01', '1 day'),
('2000-01-01', '2000-02-01', '1 month'),
('2000-02-01', '2000-03-01', '1 month'), -- month length not important
('2000-01-28', '2000-02-29', '1 month, 1 day'), -- leap years to be accounted for
('2000-01-01', '2000-12-31', '11 months, 30 days'),
('2000-02-28', '2000-03-01', '2 days'),
('2001-02-28', '2001-03-01', '1 day'), -- not a leap year
('2000-01-01', '2001-01-01', '1 year'),
('2000-01-01', '2011-01-01', '11 years'),
('9999-12-30', '9999-12-31', '1 day'), -- catch overflow in date calculations
('1900-01-01', '9999-12-31', '8099 years 11 months 30 days'); -- min(date) to max(date)
I happen to be using SQL Server 2008R2 but I am interested to learn how other dialects would handle this.
Best Answer
The following solution is for SQL Server. The approach is similar to Serg's in that the query uses only the DATEADD and DATEDIFF functions. It does not, however, account for negative intervals (FromDate > ToDate), and it derives years and months from the total month difference:
Output: