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
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