Time Zones and Daylight Saving Time

Published on: 2019-03-05

Watch this week’s episode on YouTube

AT TIME ZONE is great because it makes it easy to perform daylight saving time and time zone conversions in our queries.

However, when using AT TIME ZONE for these types of conversions there are a couple key points to remember to ensure you are getting the correct results. Let’s look at an example.

Thanks to reader Jeff Konicky for the inspiration for this post and allowing me to share it.

DST Conversions

This year, Daylight Savings Time kicks in at 2019-03-10 02:00:00 in Eastern Standard Time, meaning that the time zone switches from being 5 hours behind UTC to only 4 hours behind UTC.

If we have two datetime2s with UTC data, one right before DST kicks in and one right after, we should be able to use AT TIME ZONE to convert these UTC times to Eastern Standard/Daylight Time no problem:

    @PreDST datetime2 = '2019-03-10 06:59:00',
    @PostDST datetime2 = '2019-03-19 07:00:00';

    @PreDST AT TIME ZONE 'Eastern Standard Time' AS [PreDST should be -05:00],
    @PostDST AT TIME ZONE 'Eastern Standard Time' AS [PostDST should be -04:00];

While that sounds great, the results above show it clearly didn’t work – both of those datetime2s are showing as already being in daylight saving time (offset of -04:00).

Why did this happen?

SQL Server Doesn’t Know Your Data Is In UTC

The fallacy above is that I said our two datetime2’s are in UTC, but SQL Server doesn’t actually know this. The datetime2 (and datetime) datatype doesn’t allow for time zone offsets so SQL Server really doesn’t know what time zone the data is in.

Using AT TIME ZONE on a datetime2 without offset information causes SQL Server to “…[assume] that [the datetime] is in the target time zone”. That explains why the two datetime2s above, intended to be in UTC, are actually seen as Eastern Daylight Time by SQL Server.

Specifying the Time Zone Offset

So how do we tell SQL Server that our data is in UTC so AT TIME ZONE functions like we want?

One option is to use the assumption of AT TIME ZONE above in our favor, using it to first convert the datetime2s to UTC and then to EST:

    @PreDST AT TIME ZONE 'UTC' AT TIME ZONE 'Eastern Standard Time' AS [PreDST should be -05:00],
    @PostDST AT TIME ZONE 'UTC' AT TIME ZONE 'Eastern Standard Time' AS [PostDST should be -04:00];

Now we have the correct -05:00 and -04:00 offsets applied.

A cleaner solution would be to encode the original data by using the datetimeoffset datatype, which will indicate which time zone the datetimes are stored in:

    @PreDST datetimeoffset = '2019-03-10 06:59:00+00:00',
    @PostDST datetimeoffset = '2019-03-19 07:00:00+00:00';

    @PreDST AT TIME ZONE 'Eastern Standard Time' AS [PreDST should be -05:00],
    @PostDST AT TIME ZONE 'Eastern Standard Time' AS [PostDST should be -04:00];

Don’t Assume

Whenever working with datetime2 (or datetime) in SQL Server, you can’t assume SQL Server knows the time zone of your data. Your business logic may indicate that you store dates in UTC, but SQL Server has no way of knowing that without your code explicitly stating it using something like AT TIME ZONE ‘UTC’ or storing your data in the datetimeoffset datatype.

Thanks for reading. You might also enjoy following me on Twitter.

Want to learn even more SQL?

Sign up for my newsletter to receive weekly SQL tips!

4 thoughts on “Time Zones and Daylight Saving Time”

  1. The behavior of AT TIME ZONE is a little bit unexpected since, to me, all datetime values in the database should represent UTC values. But the behavior is actually a sensible choice because the majority of people work in only one time zone: their local time. Usually it’s the same time zone as the server where their data reside.

    While this situation is negligibly addressed by the introduction of DATETIMEOFFSET datatype regarding UTC-to-local time zone conversions, the pitfall of identifying the original time zone remains. Until there is a datatype that stores the datetime with the actual time zone it came from – something DATETIMEOFFSET deceptively does not provide – we’ll be stuck with having to perform extra work to guarantee we’re working with a known time zone.

    The simple solution you and Jeff Konicky shared helps a lot. Thank you!

  2. Did you intend both sample datetime2 values to be on the same day? I noticed the first one was March 10 and the second was March 19. I wonder if perhaps the second was just a typo – a 19 instead of a 10. It doesn’t really change the example but it wasn’t two datetime2s off by only a minute.

  3. Hi,
    Is there a different logic that helps solving the time adjustment?
    For example :
    If this change occurs every 2nd Sunday on March and also ends 1 st Sunday on November,

    How could I validate if current month and weekdays is now possible to consider this changes?

    I’m currently working with a UTC DDBB

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.