How to calculate the local datetime from a utc datetime in tsql (sql 2005)?

前端 未结 10 1365
Happy的楠姐
Happy的楠姐 2021-02-02 14:13

i want to loop over a period of time in tsql, and print the utc datetimes and our local variant. We live in UTC +1, so i could easily add 1 hour, but in the summertime we live i

10条回答
  •  悲哀的现实
    2021-02-02 14:59

    Bobman's answer is close, but has a couple bugs: 1) You must compare local DAYLIGHT time (instead of local STANDARD time) to the Daylight Saving End DateTime. 2) SQL BETWEEN is Inclusive so you should be comparing using ">= and <" instead of BETWEEN.

    Here is a working modified version along with some test cases: (Again, this only works for United States)

    -- Test cases:
    -- select dbo.fn_utc_to_est_date('2016-03-13 06:59:00.000') -- -> 2016-03-13 01:59:00.000 (Eastern Standard Time)
    -- select dbo.fn_utc_to_est_date('2016-03-13 07:00:00.000') -- -> 2016-03-13 03:00:00.000 (Eastern Daylight Time)
    -- select dbo.fn_utc_to_est_date('2016-11-06 05:59:00.000') -- -> 2016-11-06 01:59:00.000 (Eastern Daylight Time)
    -- select dbo.fn_utc_to_est_date('2016-11-06 06:00:00.000') -- -> 2016-11-06 01:00:00.000 (Eastern Standard Time)
    CREATE FUNCTION [dbo].[fn_utc_to_est_date]
    (
        @utc datetime
    )
    RETURNS datetime
    as
    begin
        -- set offset in standard time (WITHOUT daylight saving time)
        declare @offset smallint
        set @offset = -5  --EST
    
        declare @localStandardTime datetime
        SET @localStandardTime = dateadd(hh, @offset, @utc)
    
        -- DST in USA starts on the second sunday of march and ends on the first sunday of november.
        -- DST was extended beginning in 2007:
        --   https://en.wikipedia.org/wiki/Daylight_saving_time_in_the_United_States#Second_extension_.282005.29
        -- If laws/rules change, obviously the below code needs to be updated.
    
        declare @dstStartDate datetime,
                @dstEndDate datetime,
                @year int
        set @year = datepart(year, @localStandardTime)
    
        -- get the first possible DST start day
        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'
        while ((datepart(weekday,@dstStartDate) != 1)) begin --while not sunday
            set @dstStartDate = dateadd(day, 1, @dstStartDate)
        end
    
        -- get the first possible DST end day
        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'
        while ((datepart(weekday,@dstEndDate) != 1)) begin --while not sunday
            set @dstEndDate = dateadd(day, 1, @dstEndDate)
        end
    
        declare @localTimeFinal datetime,
                @localTimeCompare datetime
        -- if local date is same day as @dstEndDate day,
        -- we must compare the local DAYLIGHT time to the @dstEndDate (otherwise we compare using local STANDARD time).
        -- See: http://www.timeanddate.com/time/change/usa?year=2016
        if (datepart(month,@localStandardTime) = datepart(month,@dstEndDate)
                and datepart(day,@localStandardTime) = datepart(day,@dstEndDate)) begin
            set @localTimeCompare = dateadd(hour, 1, @localStandardTime)
        end
        else begin
            set @localTimeCompare = @localStandardTime
        end
    
        set @localTimeFinal = @localStandardTime
    
        -- check for DST
        if (@localTimeCompare >= @dstStartDate and @localTimeCompare < @dstEndDate) begin
            set @localTimeFinal = dateadd(hour, 1, @localTimeFinal)
        end
    
        return @localTimeFinal
    end
    

提交回复
热议问题