AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 28187
Accepted
Rachel
Rachel
Asked: 2012-11-06 05:25:33 +0800 CST2012-11-06 05:25:33 +0800 CST 2012-11-06 05:25:33 +0800 CST

Como posso obter o deslocamento correto entre o UTC e o horário local para uma data anterior ou posterior ao horário de verão?

  • 772

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, @localDateTimeacaba 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

sql-server sql-server-2005
  • 11 11 respostas
  • 213140 Views

11 respostas

  • Voted
  1. Best Answer
    Kevin Feasel
    2012-11-06T05:53:52+08:002012-11-06T05:53:52+08:00

    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.

    • 21
  2. adss
    2014-05-04T02:13:21+08:002014-05-04T02:13:21+08:00

    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:

    SELECT [DateTimeUtil].[UDF_ConvertUtcToLocalByTimezoneIdentifier] (
        'W. Europe Standard Time', -- the target local timezone
        '2014-03-30 00:55:00' -- the original UTC datetime you want to convert
    )
    

    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.

    • 17
  3. Ludo Bernaerts
    2014-11-21T00:16:41+08:002014-11-21T00:16:41+08:00

    Eu sempre uso este comando TSQL.

    -- the utc value 
    declare @utc datetime = '20/11/2014 05:14'
    
    -- the local time
    
    select DATEADD(hh, DATEDIFF(hh, getutcdate(), getdate()), @utc)
    
    -- or if you're concerned about non-whole-hour offsets, use:
    
    SELECT DATEADD(MINUTE, DATEDIFF(MINUTE, GETUTCDATE(), GETDATE()), @utc).
    

    É muito simples e faz o trabalho.

    • 13
  4. gotqn
    2019-02-12T05:32:59+08:002019-02-12T05:32:59+08:00

    Para SQL Server 2016+, você pode usar AT TIME ZONE . Ele irá lidar automaticamente com os horários de verão.

    • 13
  5. Rachel
    2012-11-28T11:04:12+08:002012-11-28T11:04:12+08:00

    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 @offsetvariá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 - 5

    Nã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.

    CREATE FUNCTION [dbo].[UDTToLocalTime](@UDT AS DATETIME)  
    RETURNS DATETIME
    AS
    BEGIN 
    --====================================================
    --Set the Timezone Offset (NOT During DST [Daylight Saving Time])
    --====================================================
    DECLARE @Offset AS SMALLINT
    SET @Offset = -5
    
    --====================================================
    --Figure out the Offset Datetime
    --====================================================
    DECLARE @LocalDate AS DATETIME
    SET @LocalDate = DATEADD(hh, @Offset, @UDT)
    
    --====================================================
    --Figure out the DST Offset for the UDT Datetime
    --====================================================
    DECLARE @DaylightSavingOffset AS SMALLINT
    DECLARE @Year as SMALLINT
    DECLARE @DSTStartDate AS DATETIME
    DECLARE @DSTEndDate AS DATETIME
    --Get Year
    SET @Year = YEAR(@LocalDate)
    
    --Get First Possible DST StartDay
    IF (@Year > 2006) SET @DSTStartDate = CAST(@Year AS CHAR(4)) + '-03-08 02:00:00'
    ELSE              SET @DSTStartDate = CAST(@Year AS CHAR(4)) + '-04-01 02:00:00'
    --Get DST StartDate 
    WHILE (DATENAME(dw, @DSTStartDate) <> 'sunday') SET @DSTStartDate = DATEADD(day, 1,@DSTStartDate)
    
    
    --Get First Possible DST EndDate
    IF (@Year > 2006) SET @DSTEndDate = CAST(@Year AS CHAR(4)) + '-11-01 02:00:00'
    ELSE              SET @DSTEndDate = CAST(@Year AS CHAR(4)) + '-10-25 02:00:00'
    --Get DST EndDate 
    WHILE (DATENAME(dw, @DSTEndDate) <> 'sunday') SET @DSTEndDate = DATEADD(day,1,@DSTEndDate)
    
    --Get DaylightSavingOffset
    SET @DaylightSavingOffset = CASE WHEN @LocalDate BETWEEN @DSTStartDate AND @DSTEndDate THEN 1 ELSE 0 END
    
    --====================================================
    --Finally add the DST Offset 
    --====================================================
    RETURN DATEADD(hh, @DaylightSavingOffset, @LocalDate)
    END
    
    
    
    GO
    
    • 11
  6. kkarns
    2012-11-06T08:13:12+08:002012-11-06T08:13:12+08:00

    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 UTCdatas em nosso banco de dados SQL Server se alinhassem com um algoritmo em um programa de terceiros que usava a API Java para converter de UTChora local.

    Eu gosto do CLRexemplo 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 a UTCconversã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ê?

    • 4
  7. Tim Cooke
    2015-03-10T15:36:39+08:002015-03-10T15:36:39+08:00

    Você pode fazer isso facilmente com um procedimento armazenado CLR.

    [SqlFunction]
    public static SqlDateTime ToLocalTime(SqlDateTime UtcTime, SqlString TimeZoneId)
    {
        if (UtcTime.IsNull)
            return UtcTime;
    
        var timeZone = TimeZoneInfo.FindSystemTimeZoneById(TimeZoneId.Value);
        var localTime = TimeZoneInfo.ConvertTimeFromUtc(UtcTime.Value, timeZone);
        return new SqlDateTime(localTime);
    }
    

    Você pode armazenar os fusos horários disponíveis em uma tabela:

    CREATE TABLE TimeZones
    (
        TimeZoneId NVARCHAR(32) NOT NULL CONSTRAINT PK_TimeZones PRIMARY KEY,
        DisplayName NVARCHAR(64) NOT NULL,
        SupportsDaylightSavingTime BIT NOT NULL,
    )
    

    E esse procedimento armazenado preencherá a tabela com os possíveis fusos horários em seu servidor.

    public partial class StoredProcedures
    {
        [SqlProcedure]
        public static void PopulateTimezones()
        {
            using (var sql = new SqlConnection("Context Connection=True"))
            {
                sql.Open();
    
                using (var cmd = sql.CreateCommand())
                {
                    cmd.CommandText = "DELETE FROM TimeZones";
                    cmd.ExecuteNonQuery();
    
                    cmd.CommandText = "INSERT INTO [dbo].[TimeZones]([TimeZoneId], [DisplayName], [SupportsDaylightSavingTime]) VALUES(@TimeZoneId, @DisplayName, @SupportsDaylightSavingTime);";
                    var Id = cmd.Parameters.Add("@TimeZoneId", SqlDbType.NVarChar);
                    var DisplayName = cmd.Parameters.Add("@DisplayName", SqlDbType.NVarChar);
                    var SupportsDaylightSavingTime = cmd.Parameters.Add("@SupportsDaylightSavingTime", SqlDbType.Bit);
    
                    foreach (var zone in TimeZoneInfo.GetSystemTimeZones())
                    {
                        Id.Value = zone.Id;
                        DisplayName.Value = zone.DisplayName;
                        SupportsDaylightSavingTime.Value = zone.SupportsDaylightSavingTime;
    
                        cmd.ExecuteNonQuery();
                    }
                }
            }
        }
    }
    
    • 3
  8. Michel de Ruiter
    2016-03-31T14:18:39+08:002016-03-31T14:18:39+08:00

    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_regreadfuncione, tente isso:

    CREATE TABLE #tztable (Value varchar(50), Data binary(56));
    DECLARE @tzname varchar(150) = 'SYSTEM\CurrentControlSet\Control\TimeZoneInformation'
    EXEC master.dbo.xp_regread 'HKEY_LOCAL_MACHINE', @tzname, 'TimeZoneKeyName', @tzname OUT;
    SELECT @tzname = 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\' + @tzname
    INSERT INTO #tztable
    EXEC master.dbo.xp_regread 'HKEY_LOCAL_MACHINE', @tzname, 'TZI';
    SELECT                                                                                  -- See http://msdn.microsoft.com/ms725481
     CAST(CAST(REVERSE(SUBSTRING(Data,  1, 4)) AS binary(4))      AS int) AS BiasMinutes,   -- UTC = local + bias: > 0 in US, < 0 in Europe!
     CAST(CAST(REVERSE(SUBSTRING(Data,  5, 4)) AS binary(4))      AS int) AS ExtraBias_Std, --   0 for most timezones
     CAST(CAST(REVERSE(SUBSTRING(Data,  9, 4)) AS binary(4))      AS int) AS ExtraBias_DST, -- -60 for most timezones: DST makes UTC 1 hour earlier
     -- When DST ends:
     CAST(CAST(REVERSE(SUBSTRING(Data, 13, 2)) AS binary(2)) AS smallint) AS StdYear,       -- 0 = yearly (else once)
     CAST(CAST(REVERSE(SUBSTRING(Data, 15, 2)) AS binary(2)) AS smallint) AS StdMonth,      -- 0 = no DST
     CAST(CAST(REVERSE(SUBSTRING(Data, 17, 2)) AS binary(2)) AS smallint) AS StdDayOfWeek,  -- 0 = Sunday to 6 = Saturday
     CAST(CAST(REVERSE(SUBSTRING(Data, 19, 2)) AS binary(2)) AS smallint) AS StdWeek,       -- 1 to 4, or 5 = last <DayOfWeek> of <Month>
     CAST(CAST(REVERSE(SUBSTRING(Data, 21, 2)) AS binary(2)) AS smallint) AS StdHour,       -- Local time
     CAST(CAST(REVERSE(SUBSTRING(Data, 23, 2)) AS binary(2)) AS smallint) AS StdMinute,
     CAST(CAST(REVERSE(SUBSTRING(Data, 25, 2)) AS binary(2)) AS smallint) AS StdSecond,
     CAST(CAST(REVERSE(SUBSTRING(Data, 27, 2)) AS binary(2)) AS smallint) AS StdMillisec,
     -- When DST starts:
     CAST(CAST(REVERSE(SUBSTRING(Data, 29, 2)) AS binary(2)) AS smallint) AS DSTYear,       -- See above
     CAST(CAST(REVERSE(SUBSTRING(Data, 31, 2)) AS binary(2)) AS smallint) AS DSTMonth,
     CAST(CAST(REVERSE(SUBSTRING(Data, 33, 2)) AS binary(2)) AS smallint) AS DSTDayOfWeek,
     CAST(CAST(REVERSE(SUBSTRING(Data, 35, 2)) AS binary(2)) AS smallint) AS DSTWeek,
     CAST(CAST(REVERSE(SUBSTRING(Data, 37, 2)) AS binary(2)) AS smallint) AS DSTHour,
     CAST(CAST(REVERSE(SUBSTRING(Data, 39, 2)) AS binary(2)) AS smallint) AS DSTMinute,
     CAST(CAST(REVERSE(SUBSTRING(Data, 41, 2)) AS binary(2)) AS smallint) AS DSTSecond,
     CAST(CAST(REVERSE(SUBSTRING(Data, 43, 2)) AS binary(2)) AS smallint) AS DSTMillisec
    FROM #tztable;
    DROP TABLE #tztable
    

    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.

    • 3
  9. colinp_1
    2017-04-20T08:51:11+08:002017-04-20T08:51:11+08:00

    Aqui está uma resposta escrita para um aplicativo específico do Reino Unido e baseada puramente em SELECT.

    1. Sem deslocamento de fuso horário (por exemplo, Reino Unido)
    2. Escrito para o horário de verão começando no último domingo de março e terminando no último domingo de outubro (regras do Reino Unido)
    3. 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.

      -- A variable holding an example UTC datetime in the UK, try some different values:
      DECLARE
      @App_Date datetime;
      set @App_Date = '20250704 09:00:00'
      
      -- Outputting the local datetime in the UK, allowing for daylight saving:
      SELECT
      case
      when @App_Date >= dateadd(day, 1 - datepart(weekday, dateadd(day, -1, dateadd(month, 3, dateadd(year, datediff(year, 0, @App_Date), 0)))), dateadd(day, -1, dateadd(month, 3, dateadd(year, datediff(year, 0, @App_Date), 0))))
          and @App_Date < dateadd(day, 1 - datepart(weekday, dateadd(day, -1, dateadd(month, 10, dateadd(year, datediff(year, 0, @App_Date), 0)))), dateadd(day, -1, dateadd(month, 10, dateadd(year, datediff(year, 0, @App_Date), 0))))
          then DATEADD(hour, 1, @App_Date) 
      else @App_Date 
      end
      
    • 2
  10. Joost Versteegen
    2018-06-26T05:48:55+08:002018-06-26T05:48:55+08:00
    DECLARE @TimeZone VARCHAR(50)
    EXEC MASTER.dbo.xp_regread 'HKEY_LOCAL_MACHINE', 'SYSTEM\CurrentControlSet\Control\TimeZoneInformation', 'TimeZoneKeyName', @TimeZone OUT
    SELECT @TimeZone
    DECLARE @someUtcTime DATETIME
    SET @someUtcTime = '2017-03-05 15:15:15'
    DECLARE @TimeBiasAtSomeUtcTime INT
    SELECT @TimeBiasAtSomeUtcTime = DATEDIFF(MINUTE, @someUtcTime, @someUtcTime AT TIME ZONE @TimeZone)
    SELECT DATEADD(MINUTE, @TimeBiasAtSomeUtcTime * -1, @someUtcTime)
    
    • 1

relate perguntas

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

  • Downgrade do SQL Server 2008 para 2005

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como ver a lista de bancos de dados no Oracle?

    • 8 respostas
  • Marko Smith

    Quão grande deve ser o mysql innodb_buffer_pool_size?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    restaurar a tabela do arquivo .frm e .ibd?

    • 10 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Como selecionar a primeira linha de cada grupo?

    • 6 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    pedrosanta Listar os privilégios do banco de dados usando o psql 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST
  • Martin Hope
    bernd_k Quando devo usar uma restrição exclusiva em vez de um índice exclusivo? 2011-01-05 02:32:27 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve