Converting UTC time to local time or EU daylight comparision - sql

Select a, b, c, FROM x
JOIN y ON x.x=y.x
AND x.PlannedDateTime BETWEEN y.FromDateTime and y.ToDateTime
Plannedsate time is local time ( e.g. 2018-03-07 14:03:00.000)
FromDateTime is UTC (2018-03-07 14:03:00.000 +01:00) I dont know UTC or daylight in EU
ToDateTime is UTC (2018-03-07 15:27:00.000 +01:00) I dont know UTC or daylight in EU
When I join on these dates as above written query I miss many records. I think due to different time format.
Please provide any solution thanks in advance

As specified in the comments, in SQL Server 2016 or later, you should use AT TIME ZONE to convert a datetimeoffset to a specific timezone. To convert a datetimeoffset to the local time zone of the server, you first have to find it and then you can use it like this:
DECLARE #TimeZone VARCHAR(50)
EXEC master.dbo.xp_regread 'HKEY_LOCAL_MACHINE', 'SYSTEM\CurrentControlSet\Control\TimeZoneInformation', 'TimeZoneKeyName',#TimeZone OUT
SELECT #TimeZone
DECLARE #x DATETIMEOFFSET='2018-03-07 14:03:00.000 +01:00'
SELECT #x AT TIME ZONE #TimeZone
DECLARE #y DATETIMEOFFSET='2018-04-07 14:03:00.000 +01:00'
SELECT #y AT TIME ZONE #TimeZone
On my computer (located in Bucharest, Romania, which is also part of the European Union) the above query returns:
GTB Standard Time
2018-03-07 15:03:00.0000000 +02:00
2018-04-07 16:03:00.0000000 +03:00
As you can see, this takes into account the daylight savings time which would be in effect or not at the specified date.
Instead of the timezone of the server (or if you cannot use xp_regread due to permission issues), you may want to use a specific timezone, for example 'Central Europe Standard Time'.

Related

Can you make SQL Server datetimeoffset "nullable"?

I have an API that receives datetimeoffsets, and stored in a SQL Server in a DateTimeOffset column. However, some of the users of the API do not have the timezone information.
In that case, the system treat this like it is UTC.
I there any clever way to fool the SQL Server into having the timezone information optional/nullable?
In that case I could transform it to localtime if there was timezone information, or just show the datetime unmodified if no timezone information was present.
You cannot remove the offset from datetimeoffset datatype. Some workarounds:
Use datetimeoffset and datetime2 columns and populate one or the other depending on whether the input contains timezone information or not.
Use datetime2 to store the datetime part of the input and varchar(6) to store the timezone offset, if present.
Use at time zone to convert the input to a specific timezone and store the result as datetimeoffset. Here is an example:
select cast('2022-01-01 12:00:00 -05:00' as datetimeoffset); -- 2022-01-01 12:00:00 -05:00
select cast('2022-06-01 12:00:00 -04:00' as datetimeoffset); -- 2022-06-01 12:00:00 -04:00
select cast('2022-01-01 12:00:00' as datetime2) at time zone 'Eastern Standard Time'; -- 2022-01-01 12:00:00 -05:00
select cast('2022-06-01 12:00:00' as datetime2) at time zone 'Eastern Standard Time'; -- 2022-06-01 12:00:00 -04:00
The conclusion is: No, it is not possible.
You have to find another way to solve the problem.

SQL time in incorrect from that of my system timezone

We have a SQL database that returns all the times in Greenwich Mean Time (GMT). We are in the Eastern Standard Timezone (EST). This messes up some queries that we have that pull data from specific dates. I tried using the (StartTime AT TIME ZONE 'Eastern Standard Time' as StartTime_ET, but that only returns the result as same in GMT -5. I just want the exact result to be in EST .
This changes the complete logic process of mine. Is there any way to do that?
Assuming your values are all UTC and that your column StartTime is not a datetimeoffset, then you need to turn your value into a datetimeoffset first, and then change the time zone. When you use AT TIMEZONE on a date and time data type that isn't a DATETIMEOFFSET it is assumed that the value is already at the correct timezone. Therefore, for example something like SELECT GETUTCDATE() AT TIME ZONE 'Eastern Standard Time'; would return 2021-08-05 09:53:56.8500000 -04:00 right now, even though the time in EST is actually 2021-08-05 05:53:56.8500000 -04:00 right now.
As a result you need to add the offset first and then use AT TIME ZONE. So, with GETUTCDATE that would be like this:
SELECT SWITCHOFFSET(GETUTCDATE(),0) AT TIME ZONE 'Eastern Standard Time';
Therefore, presumably, you just need to do the same for your column, StartTime, which is also a UTC time:
SWITCHOFFSET(StartTime,0) AT TIME ZONE 'Eastern Standard Time'
If you don't want the timezone portion, then you can convert it back to a different date and time data type:
CONVERT(datetime2(0),SWITCHOFFSET(StartTime,0) AT TIME ZONE 'Eastern Standard Time')

Get a specific date in a specific time zone

I am trying to derive a given date from a DB that is in Greenwich Mean Time. so I need to constantly account for the discrepancy.
DECLARE #date datetime
DECLARE #tempdate datetime = '3/1/2019'
SET #date = #tempdate AT TIME ZONE 'UTC' AT TIME ZONE 'Central Standard
Time'
SELECT #date
The above code produces a date several hours before March 1st (since I am in the U.S.). Is there a generic way to always grab Central Time for any desired date?
IF you are trying to convert UTC time into US Central Time it is indeed normal to receive a Central time that is earlier that UTC time. Sun rises in Greenwich first and sometime later rises in Chicago, so the March begins first in UTC zone, few hours prior to doing it in Chicago. Same goes for other months! :)

TSQL Date conversion

I have a SQL table with datetime2 objects, and they are stored in UTC TIME
for example
UTC_TIME = 2017-10-20T13:16:14.6950000
I have successfully converted this timestamp to local time using
SELECT UTC_TIME AT TIME ZONE 'W. Europe Standard Time' AS LOCAL_TIME
The output of the above is
2017-10-20T13:16:14.6950000+02:00
This is correct, but the output I want is
2017-10-20T15:16:14.6950000
The offset should be added to my timestamp.
Is there an easy way to do this ?
Example :
An event was logged on UTC time 2017-10-20T13:16:14.6950000
I'm in Western Europe, and for the moment there is an offset of 2 hours. So the actual local time is 2017-10-20T15:16:14.6950000
I would like to convert the UTC time (13:16), so that the result is 15:16
The query is executed on a server that runs in UTC timezone.
As AT TIME ZONE returns a DateTimeOffset you can use CONVERT with option 1.
DECLARE #UTC_TIME DATETIME2(7) = '2017-10-20T13:16:14.6950000'
SELECT CONVERT(datetime2, (#UTC_TIME AT TIME ZONE 'Pacific Standard Time'), 1) AS OrderDate_TimeZonePST
See also CAST and CONVERT (Transact-SQL)
You can do this using sysdatetimeoffset
declare #UTC_Time datetime2 = '2017-10-20T13:16:14.6950000'
Select dateadd(minute, datepart(TZoffset, sysdatetimeoffset()), #UTC_Time)
This seems the way to do it :
DECLARE #UTC_TIME DATETIME2(7) = '2017-10-20T13:16:14.6950000'
SELECT
#UTC_TIME AS T0,
#UTC_TIME AT TIME ZONE 'W. Europe Standard Time' AS T1,
dateadd(minute,DATEdiff(minute,#UTC_TIME AT TIME ZONE 'W. Europe Standard Time',#UTC_TIME ),#UTC_TIME) as T2
The result is
T0 : 2017-10-20T13:16:14.6950000
T1 : 2017-10-20T13:16:14.6950000+02:00
T2 : 2017-10-20T15:16:14.6950000
T2 is what we would see on the local clock for an event happening at UTC time T0

SQL DateTimes stored in UTC get beginning of day based on offset

This may be the most pathetic question ever asked related to SQL and date/time values, but I could use some help...
Trying to setup a function/job that will run at a specified time or times in eastern, mountain, central, and pacific time zones (in theory other zones would work too). The system will identify which users belong to each timezone and then output data from the system highlighting what they've accomplished for the current day.
Here is my challenge, I know all date/time values are stored on the SQL DB in UTC. I can apply the offset and convert those times to local time zones. Rather than convert tens of thousands of date/time values to local time and make comparisons there, it'd be cleaner (I think) to simply adjust the beginning and ending date/time values of UTC within the stored procedure.
On the west coast it is currently just about 2017-09-30 14:30:00 and in UTC is 2017-09-30 21:30:00, this clearly demonstrates a 7 hour time zone difference right now which means "today" from a user perspective technically started at 2017-09-30 07:00:00 and will end on 2017-10-01 06:59:999 in UTC.
What is the best way of establishing these date/time values for a users beginning of day and ending of day values?
UPDATES
I currently have this code...
DECLARE #InputDate as DateTime
DECLARE #InputEndDate as DateTime
DECLARE #InputDateWithOffset as DateTimeOffSet
DECLARE #InputEndDateWithOffset as DateTimeOffSet
SET #InputDate = '2017-09-28'
SET #InputDateWithOffset = #InputDate AT TIME ZONE 'UTC' AT TIME ZONE 'Pacific Standard Time'
SET #InputEndDate = DATEADD(day, 1, DATEADD(ms, -3, #InputDate))
SET #InputEndDateWithOffset = #InputEndDate AT TIME ZONE 'UTC' AT TIME ZONE 'Pacific Standard Time'
SELECT
#InputDate AS InputDate, #InputEndDate AS InputEndDate,
#InputDateWithOffset AS InputDateWithOffset,
#InputEndDateWithOffset AS InputEndDateWithOffset
Which outputs the following:
The last two columns appear to be correct as it would represent both the beginning of the Input Date and the ending of the Input Date as the Input Date is going to be the local date of the execution...
When I take the #InputDateWithOffset and #InputEndDateWithOffset against my table values with datetimes in UTC, it appears the only dates being returned are those that fall on 2017-09-28 and seems to disregard the comparisons to the Offset date/times.
Your update is mostly correct. However, you're missing a "start of day" operation, which needs to be done in local time.
Consider:
DECLARE #InputStartUTC as DATETIME, #InputEndUTC as DATETIME
DECLARE #InputStartDTO as DATETIMEOFFSET, #InputEndDTO as DATETIMEOFFSET
DECLARE #InputStartDTOatStartOfDay as DATETIMEOFFSET,
#InputEndDTOatStartOfDay as DATETIMEOFFSET
DECLARE #tz as VARCHAR(50) = 'Pacific Standard Time'
SET #InputStartUTC = '2017-09-28 00:00:00'
SET #InputStartDTO = #InputStartUTC AT TIME ZONE 'UTC' AT TIME ZONE #tz
SET #InputStartDTOatStartOfDay = CAST(CAST(#InputStartDTO as DATE) as DATETIME)
AT TIME ZONE #tz
SET #InputEndUTC = DATEADD(day, 1, #InputStartUTC)
SET #InputEndDTO = #InputEndUTC AT TIME ZONE 'UTC' AT TIME ZONE #tz
SET #InputEndDTOatStartOfDay = CAST(CAST(#InputEndDTO as DATE) as DATETIME)
AT TIME ZONE #tz
SELECT
#InputStartUTC as InputStartUTC, #InputEndUTC as InputEndUTC,
#InputStartDTO as InputStartDTO, #InputEndDTO as InputEndDTO,
#InputStartDTOatStartOfDay as InputStartDTOatStartOfDay,
#InputEndDTOatStartOfDay as InputEndDTOatStartOfDay
Also, notice I did not subtract three milliseconds from your end date. Rather than trying to figure out .997 or .999 or whatever, the better approach is to query using a half-open interval. In other words, start <= value AND end > value.