В недавнем проекте требовалось сообщать, когда ресурс будет полностью использован. Помимо календарной даты исчерпания, меня попросили показать оставшееся время в английском формате, например, «1 год, 3 месяца вперед».
Встроенная DATEDIFF
функция
Возвращает количество ... указанных границ части даты, пересекаемых между указанной начальной датой и конечной датой.
Если используется как есть, это может привести к ошибочным или запутанным результатам. Например, использование интервала YEAR покажет 1999-12-31 (ГГГГ-ММ-ДД) и 2000-01-01 с интервалом в один год, тогда как здравый смысл скажет, что эти даты разделены только одним днем. И наоборот, используя интервал ДЕНЬ 1999-12-31 и 2010-12-31 разделены на 4 018 дней, в то время как большинство людей увидят "11 лет" как лучшее описание.
Если исходить из количества дней и расчета месяцев и лет, это может привести к ошибкам високосного года и размера месяца.
Мне стало интересно, как это можно реализовать на различных диалектах SQL? Пример вывода включает в себя:
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)
Я использую SQL Server 2008R2, но мне интересно узнать, как другие диалекты справятся с этим.