It’s Time – Checking and Adjusting for Daylight Saving Time

Author: David Tufte Posted In: Data

Ever need to join data sources from different time zones? Here’s a scenario I recently faced, and how I worked around it.

I needed to join several tables together from two different data sources. One data source was captured in UTC, while the other was local time zone, including Daylight Saving Time (DST) considerations. An additional challenge was that the data source that was in local time zone, can be in different time zones. I did have access to a geography dimension that had the time zones and the number of hours offset from UTC.

I know that there are SQL Server specific time offset options, but for a variety of reasons, I needed a more generic option to deal with the time zone and DST factors. That meant I needed to create an approach to check to see if a datetime was in Daylight Saving Time or not. I thought I would be able to find a reference table, but that meant I would need to be able to build one.

The code

Here’s the code I wrote to build a temp table that had the DST Start and DST End datetimes for each year I needed to compare, and you can see how I did the compare to change the time to DST:

IF OBJECT_ID('tempdb..#DST_Date') IS NOT NULL
DROP TABLE #DST_Date;

CREATE TABLE #DST_Date(
   Date_Key  datetime NOT NULL
 , DstStart  datetime NOT NULL
 , DstEnd  datetime NOT NULL
) ON [PRIMARY]
declare   @i               INT 
        , @date            DATETIME
        , @enddate         DATETIME
        , @StartDate       DATETIME
        , @year            INT 
        , @StartOfMarch    DATETIME 
        , @StartOfNovember DATETIME 
        , @DstStart        DATETIME 
        , @DstEnd          DATETIME
set @i = (select DATEDIFF(dd,'2018-01-01','2018-01-01'))                            --  Set the starting date of the table
set @StartDate ='2018-01-01'
set @enddate = DATEADD(yy,(DATEDIFF(yy,'2018-01-01', getdate())) + 1,'2018-12-31')  -- One year more than current year
while @i <= (select DATEDIFF(dd,'2018-01-01',@enddate))                             --  Set the ending date of the table
begin
set @year = DATEPART(YYYY,(DATEADD(dd,@i,@StartDate)))
SET @StartOfMarch = DATEADD(MONTH, 2, DATEADD(YEAR, @year - 1900, 0))
SET @StartOfNovember = DATEADD(MONTH, 10, DATEADD(YEAR, @year - 1900, 0));
SET @DstStart = DATEADD(HOUR, 2,
     DATEADD(day,
       ( ( 15 - DATEPART(dw, @StartOfMarch) ) % 7 )
        + 7, @StartOfMarch))
SET @DstEnd   = DATEADD(HOUR, 2,
     DATEADD(day,
       ( ( 8 - DATEPART(dw, @StartOfNovember) ) % 7 ),
        @StartOfNovember))
SET @date =  (DATEADD(dd,@i,@StartDate))
INSERT INTO #DST_Date 
(
   [Date_Key],
   [DstStart],
   [DstEnd] 
)
VALUES
(
  DATEADD(dd,@i,@StartDate),
      @DstStart, 
      @DstEnd
)  
   set @i = @i + 1
 end;

DECLARE @testDate    datetime = '2018-03-11 01:01:00.000',
        @testDSTDate datetime = '2018-03-11 02:01:00.000'
   
select Date_Key, DstStart, DstEnd , 
   @testDate                                                            AS testDate  ,
    CASE 
     WHEN  @testDate Between DstStart AND DstEnd
     THEN 1
     ELSE 0
    END                                                                 AS IN_DST,
    CASE 
     WHEN @testDate Between DstStart AND DstEnd
     THEN (DATEADD(ss,(3600), @testDate)) 
     ELSE  @testDate
    END                                                                 AS testDateDST_Time,
      @testDSTDate                                                      AS testDSTDate  ,
    CASE 
     WHEN  @testDSTDate Between DstStart AND DstEnd
     THEN 1
     ELSE 0
    END                                                                 AS DSTin_DST,
    CASE 
     WHEN @testDSTDate Between DstStart AND DstEnd
     THEN (DATEADD(ss,(3600), @testDSTDate)) 
     ELSE  @testDSTDate
    END                                                                 AS testDSTDateDST_Time
 from #DST_Date 
where CAST( @testDate  as DATE) = Date_Key

SELECT * FROM #DST_Date

Here is the output of the test and a sample of the DST_Test temp table: