Estou tentando escrever uma consulta que agrupe registros com base na parte da data local apenas de um campo de data e hora UTC.
Por exemplo, se minha tabela contiver 10/19/2012 2:00:00
, ela deverá ser agrupada como 10/18/2012
, pois meu horário local é EST (-5h) e estou interessado apenas na parte de data do campo.
Sei que posso usar DateAdd(day, DateDiff(day, 0, MyDate), 0)
para obter a parte da data apenas do campo datetime e posso usar DateAdd(minute, DateDiff(minute, GetUtcDate(), GetDate()), MyUtcDate)
para converter uma data e hora UTC em uma data e hora local.
Mas combinar os dois está me ofendendo seriamente.
Existe uma maneira melhor do que essa de obter apenas a parte Date de um campo UTC DateTime, convertido em hora local, no SQL Server 2005?
SELECT DateAdd(day, DateDiff(day, 0, DateAdd(minute, DateDiff(minute, GetUtcDate(), GetDate()), MyUtcDate)), 0)
, Count(*)
FROM MyTable
GROUP BY DateAdd(day, DateDiff(day, 0, DateAdd(minute, DateDiff(minute, GetUtcDate(), GetDate()), MyUtcDate)), 0)
Esta resposta não leva em consideração as mudanças no horário de verão, a adição de segundos bissextos e é insensível a fusos horários que não são deslocamentos de hora inteira do UTC. Consulte minha segunda resposta a esta pergunta para obter uma maneira muito mais precisa de fazer isso para o SQL Server 2016 e superior.
Se você não é avesso a ter uma função fazendo o trabalho sujo, isso ajuda a tornar a instrução mais limpa:
Você poderia então fazer algo como:
O código acima truncará qualquer parte do tempo da entrada de data para a função (isso é por design). Portanto, conforme observado no início da minha resposta, todos os fusos horários que implementam minutos, como a Ilha do Príncipe Eduardo no Canadá (UTC -4:30), Índia (UTC -4:30) e Kathmandu (UTC +5:45 ), não verá resultados corretos.
Esteja ciente de que usar uma função como essa em um grande número de linhas será péssimo para o desempenho. A
AT TIME ZONE
construção mostrada abaixo não sofre tanto com esse problema, embora não seja de forma alguma uma bala de prata em termos de desempenho.Normalmente, eu uso essa expressão
Mas no SQL Server 2008, isso simplifica para
Além de fornecer expressões alternativas aqui, se você é um purista T-SQL casado com funções DATE para manipular datas e horas, não acho que haja uma maneira mais concisa de obter a hora local além de usar uma função escalar.
No SQL Server 2016 e superior, use a
AT TIME ZONE 'timezone'
construção para converter valores de data e hora entre fusos horários.AT TIME ZONE
leva em consideração as mudanças necessárias ao longo dos anos para estar em conformidade com coisas como horário de verão, etc.Este primeiro bit configura alguns dados de amostra para usarmos:
Em seguida, pegamos os dados de amostra e os colocamos em uma tabela temporária intermediária, usando
AT TIME ZONE
para criar uma cópia da coluna de data primeiro no fuso horário "Central Standard Time" e, em seguida, apenas a parte da data desse horário.A consulta agrupada por data torna-se super fácil:
A saída agrupada para uma amostra das linhas:
Os dados subjacentes para essas linhas:
Estes dados mostram a transição do horário padrão para o horário de verão em 2022: