SQL Server - Convert date field to UTC

前端 未结 12 734
故里飘歌
故里飘歌 2020-12-23 13:39

I have recently updated my system to record date/times as UTC as previously they were storing as local time.

I now need to convert all the local stored date/times to

12条回答
  •  臣服心动
    2020-12-23 13:53

    Here is a tested procedure that upgraded my database from local to utc time. The only input required to upgrade a database is to enter the number of minutes local time is offset from utc time into @Offset and if the timezone is subject to daylight savings adjustments by setting @ApplyDaylightSavings.

    For example, US Central Time would enter @Offset=-360 and @ApplyDaylightSavings=1 for 6 hours and yes apply daylight savings adjustment.

    Supporting Database Function


    CREATE FUNCTION [dbo].[GetUtcDateTime](@LocalDateTime DATETIME, @Offset smallint, @ApplyDaylightSavings bit) 
    RETURNS DATETIME AS BEGIN 
    
        --====================================================
        --Calculate the Offset Datetime
        --====================================================
        DECLARE @UtcDateTime AS DATETIME
        SET @UtcDateTime = DATEADD(MINUTE, @Offset * -1, @LocalDateTime)
    
        IF @ApplyDaylightSavings = 0 RETURN @UtcDateTime;
    
        --====================================================
        --Calculate the DST Offset for the UDT Datetime
        --====================================================
        DECLARE @Year as SMALLINT
        DECLARE @DSTStartDate AS DATETIME
        DECLARE @DSTEndDate AS DATETIME
    
        --Get Year
        SET @Year = YEAR(@LocalDateTime)
    
        --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)
    
        --Finally add the DST Offset if needed 
        RETURN CASE WHEN @LocalDateTime BETWEEN @DSTStartDate AND @DSTEndDate THEN 
            DATEADD(MINUTE, -60, @UtcDateTime) 
        ELSE 
            @UtcDateTime
        END
    
    END
    GO
    

    Upgrade Script


    1. Make a backup before running this script!
    2. Set @Offset & @ApplyDaylightSavings
    3. Only run once!

    begin try
        begin transaction;
    
        declare @sql nvarchar(max), @Offset smallint, @ApplyDaylightSavings bit;
    
        set @Offset = -360;             --US Central Time, -300 for US Eastern Time, -480 for US West Coast
        set @ApplyDaylightSavings = 1;  --1 for most US time zones except Arizona which doesn't observer daylight savings, 0 for most time zones outside the US
    
        declare rs cursor for
        select 'update [' + a.TABLE_SCHEMA + '].[' + a.TABLE_NAME + '] set [' + a.COLUMN_NAME + '] = dbo.GetUtcDateTime([' + a.COLUMN_NAME + '], ' + cast(@Offset as nvarchar) + ', ' + cast(@ApplyDaylightSavings as nvarchar) + ') ;'
        from INFORMATION_SCHEMA.COLUMNS a
            inner join INFORMATION_SCHEMA.TABLES b on a.TABLE_SCHEMA = b.TABLE_SCHEMA and a.TABLE_NAME = b.TABLE_NAME
        where a.DATA_TYPE = 'datetime' and b.TABLE_TYPE = 'BASE TABLE' ;
    
        open rs;
        fetch next from rs into @sql;
        while @@FETCH_STATUS = 0 begin
            exec sp_executesql @sql;
            print @sql;
            fetch next from rs into @sql;
        end
        close rs;
        deallocate rs;
    
        commit transaction;
    end try
    begin catch
        close rs;
        deallocate rs;
    
        declare @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int;
        select @ErrorMessage = ERROR_MESSAGE() + ' Line ' + cast(ERROR_LINE() as nvarchar(5)), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE();
        rollback transaction;
        raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState);
    end catch
    

提交回复
热议问题