Um requisito em um projeto recente era relatar quando um recurso seria totalmente consumido. Além da data do esgotamento, pediram-me para mostrar o tempo restante no formato de inglês, algo como "daqui a 1 ano e 3 meses".
A DATEDIFF
função embutida
Retorna a contagem ... dos limites do período especificado cruzados entre a data inicial e a data final especificadas.
Se usado como está, pode produzir resultados enganosos ou confusos. Por exemplo, o uso de um intervalo de ANO mostraria 1999-12-31 (AAAA-MM-DD) e 2000-01-01 com um ano de diferença, enquanto o senso comum diria que essas datas são separadas por apenas 1 dia. Por outro lado, o intervalo de DAY 1999-12-31 e 31/12/2010 é separado por 4.018 dias, enquanto a maioria das pessoas consideraria "11 anos" como uma descrição melhor.
A partir do número de dias e do cálculo de meses e anos a partir daí, haveria tendência a erros de ano bissexto e tamanho do mês.
Eu comecei a me perguntar como isso poderia ser implementado nos vários dialetos SQL? Exemplo de saída inclui:
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)
Por acaso, estou usando o SQL Server 2008R2, mas estou interessado em saber como outros dialetos lidariam com isso.