Atualmente, uso o seguinte para obter um datetime local de um datetime UTC:
SET @offset = DateDiff(minute, GetUTCDate(), GetDate())
SET @localDateTime = DateAdd(minute, @offset, @utcDateTime)
Meu problema é que, se o horário de verão ocorrer entre GetUTCDate()
e @utcDateTime
, @localDateTime
acaba sendo uma hora de folga.
Existe uma maneira fácil de converter de utc para hora local para uma data que não seja a data atual?
Estou usando o SQL Server 2005
A melhor maneira de converter uma data UTC não atual em hora local, anterior ao SQL Server 2016, é usar o Microsoft .Net Common Language Runtime, ou CLR.
O código em si é fácil; a parte difícil geralmente é convencer as pessoas de que o CLR não é puro mal ou assustador...
Para um dos muitos exemplos, confira a postagem do blog de Harsh Chawla sobre o tópico .
Infelizmente, não há nada integrado antes do SQL Server 2016 que possa lidar com esse tipo de conversão, exceto soluções baseadas em CLR. Você poderia escrever uma função T-SQL que faça algo assim, mas então você teria que implementar a lógica de mudança de data por conta própria, e eu chamaria isso decididamente de não fácil.
Desenvolvi e publiquei o projeto T-SQL Toolbox no codeplex para ajudar qualquer pessoa que tenha dificuldades com a manipulação de data e hora e fuso horário no Microsoft SQL Server. É de código aberto e totalmente gratuito para usar.
Ele oferece UDFs de conversão de data e hora fáceis usando T-SQL simples (sem CLRs), além de tabelas de configuração pré-preenchidas prontas para uso. E tem suporte completo para DST (horário de verão).
Uma lista de todos os fusos horários com suporte pode ser encontrada na tabela "DateTimeUtil.Timezone" (fornecida no banco de dados T-SQL Toolbox).
No seu exemplo, você pode usar o seguinte exemplo:
Isso retornará o valor de data e hora local convertido.
Infelizmente, há suporte para SQL Server 2008 ou posterior apenas devido aos tipos de dados mais recentes (DATE, TIME, DATETIME2). Mas como o código-fonte completo é fornecido, você pode ajustar facilmente as tabelas e UDFs substituindo-as por DATETIME. Não tenho um MSSQL 2005 disponível para teste, mas deve funcionar com o MSSQL 2005 também. Em caso de dúvidas, é só avisar.
Eu sempre uso este comando TSQL.
É muito simples e faz o trabalho.
Para SQL Server 2016+, você pode usar AT TIME ZONE . Ele irá lidar automaticamente com os horários de verão.
Encontrei esta resposta no StackOverflow que fornece uma função definida pelo usuário que parece traduzir com precisão os datetimes
A única coisa que você precisa modificar é a
@offset
variável na parte superior para defini-la para o deslocamento de fuso horário do servidor SQL que executa essa função. No meu caso, nosso servidor SQL usa EST, que é GMT - 5Não é perfeito e provavelmente não funcionará para muitos casos, como deslocamentos TZ de meia hora ou 15 minutos (para aqueles que eu recomendaria uma função CLR como Kevin recomendado ), no entanto, funciona bem o suficiente para a maioria dos fusos horários genéricos no Norte América.
Existem algumas boas respostas para uma pergunta semelhante feita no Stack Overflow. Acabei usando uma abordagem T-SQL da segunda resposta de Bob Albright para limpar uma bagunça causada por um consultor de conversão de dados.
Funcionou para quase todos os nossos dados, mas depois percebi que seu algoritmo só funciona para datas de 5 de abril de 1987 , e tivemos algumas datas da década de 1940 que ainda não foram convertidas corretamente. Em última análise, precisávamos que as
UTC
datas em nosso banco de dados SQL Server se alinhassem com um algoritmo em um programa de terceiros que usava a API Java para converter deUTC
hora local.Eu gosto do
CLR
exemplo na resposta de Kevin Feasel usando o exemplo de Harsh Chawla, e também gostaria de compará-lo com uma solução que usa Java, já que nosso front-end usa Java para fazer aUTC
conversão para hora local.A Wikipedia menciona 8 emendas constitucionais diferentes que envolvem ajustes de fuso horário anteriores a 1987, e muitas delas são muito localizadas em diferentes estados, então há uma chance de que o CLR e o Java possam interpretá-las de maneira diferente. O código do seu aplicativo front-end usa dotnet ou Java, ou as datas anteriores a 1987 são um problema para você?
Você pode fazer isso facilmente com um procedimento armazenado CLR.
Você pode armazenar os fusos horários disponíveis em uma tabela:
E esse procedimento armazenado preencherá a tabela com os possíveis fusos horários em seu servidor.
O SQL Server versão 2016 resolverá esse problema de uma vez por todas . Para versões anteriores, uma solução CLR provavelmente é mais fácil. Ou para uma regra de horário de verão específica (como apenas nos EUA), uma função T-SQL pode ser relativamente simples.
No entanto, acho que uma solução T-SQL genérica pode ser possível. Desde que
xp_regread
funcione, tente isso:Uma função T-SQL (complexa) pode usar esses dados para determinar o deslocamento exato para todas as datas durante a regra de horário de verão atual.
Aqui está uma resposta escrita para um aplicativo específico do Reino Unido e baseada puramente em SELECT.
Não aplicável entre meia-noite e 1h no início do horário de verão. Isso pode ser corrigido, mas o aplicativo para o qual foi escrito não exige isso.