Calculate time at specific Timezone, from UTC Time - sql

I want to calculate Datetime at given timezone based on Datetime in UTC.
I thought that I can do it with the following:
DECLARE #timeUTC DATETIME = '2019-01-01 10:00:00'
SELECT
#timeUTC AS timeUTC,
#timeUTC AT TIME ZONE 'Central European Standard Time' as at_time_zone_offset,
CONVERT(datetime, #timeUTC AT TIME ZONE 'Central European Standard Time',1) at_timezone_convert
-- OUTPUT
---timeUTC |at_time_zone_offset |at_timezone_convert
---2019-01-01 10:00:00.000 |2019-01-01 10:00:00.000 +01:00 |2019-01-01 09:00:00.000
The problem is that result of at_timezone_convert is incorrect- when at UTC time is 10:00, then time +1 is 11:00, not 9.
How can I get the result to be 2019-01-01 11:00:00.000?

At time zone documentation clearly states:
Converts an inputdate to the corresponding datetimeoffset value in the target time zone. When inputdate is provided without offset information, the function applies the offset of the time zone assuming that inputdate is in the target time zone. If inputdate is provided as a datetimeoffset value, then AT TIME ZONE clause converts it into the target time zone using the time zone conversion rules.
(emphasis mine)
If you'll declare #timeUTC as DateTimeOffset and not as DateTime you'll get different results - also, note that once you've converted the DateTimeOffset back to DateTime you'll get funky results.
Also, please note that the yyyy-mm-dd hh:mm:ss string representation format is a localized format when working with DateTime - that is not the case with the newer DateTime2 data type, which is one more reason why you should never work with DateTime again.
See a demo on DB<>Fiddle

Here's a trick I use from time to time:
DECLARE #timeUTC DATETIME = '2019-01-01 10:00:00'
SELECT #timeUTC
AS timeUTC, #timeUTC
AT TIME ZONE 'UTC'
AT TIME ZONE 'Central European Standard Time'
as at_time_zone_offset
Why does this work? Your original datetime has no offset information attached to it (other posters here have explained what the default is when this is the case) The first at time zone clause tells SQL Server "this datetime represents a time in UTC" and outputs a datetimeoffset data type. The second at time zone clause then tells it to convert it to your desired time zone.

Supplying the input as a datetimeoffset the AT TIME ZONE hint will convert to the input to the target time zone.
The snippet below is a simple example:
DECLARE #Utc DATETIME = '2019-01-01 10:00:00';
DECLARE #UtcOffset datetimeoffset(7) = #Utc;
SELECT
#Utc Utc,
#UtcOffset UtcOffset,
#UtcOffset AT TIME ZONE 'Central European Standard Time' UtcConverted;
-- Results
-- Utc 1/1/2019 10:00:00 AM
-- UtcOffset 1/1/2019 10:00:00 AM +00:00
-- UtcConverted 1/1/2019 11:00:00 AM +01:00

Zohar Peled explained it just fine, but just in case, here is a code example:
DECLARE #timeUTC DATETIME = '2019-01-01 10:00:00';
SELECT
#timeUTC AS timeUTC,
#timeUTC AT TIME ZONE 'Central European Standard Time' as at_time_zone_offset,
CONVERT(datetime, cast (#timeUTC AT TIME ZONE 'Central European Standard Time' as datetimeoffset),1) at_timezone_convert,
CAST(CAST(#timeUTC AS datetimeoffset) AT TIME ZONE 'Central European Standard Time' AS datetime) AS ResultYouNeeded;

Related

Compare datetimeoffset with timezone SQL

I have a date emp_date which is of type datetime offset. This date is saved correctly in the database.
I want to retrieve all data having the date emp_date less than the actual time, including time zone.
For example, if the emp_date is as below:
2019-10-25 23:44:09.5798885 +14:00
And I am in a time zone of +2, then the data having the above date should not be retrieved.
Any idea of how to do this?
I want to pass the timezone of the user as parameter.
https://dzone.com/articles/dates-and-times-in-sql-server-at-time-zone
pass the needed time zone as parameter, then we can convert to the needed time zone.
DECLARE #TimeZone varchar(50)
SET #TimeZone = 'Central European Standard Time'
SELECT getdate() AT TIME ZONE #TimeZone AS date
SELECT getdate() AT TIME ZONE 'Central European Standard Time' AS date

SQL Server - Display EST as PST?

Server is in NY and date column (DateTime) is being filled as EST. How do users in California view this DateTime as the local PST?
I tried:
declare #dte DateTime = '20190919 10:01:01'
select #dte EST, #dte At Time Zone 'Pacific Standard Time' As PST
And I get
EST
2019-09-19 10:01:01.000
PST
2019-09-19 10:01:01.000 -07:00
I am looking for 2019-09-19 07:01:01.000 -07:00
Jeroen already said this in his comment, but I'm making the code concrete so you can see what he means.
Take your initial date, that you know the time zone for, but SQL Server doesn't yet, and tell it the time zone explicitly:
DECLARE #dte datetime = '20190919 10:01:01';
SELECT
#dte AT TIME ZONE 'Eastern Standard Time';
That returns a DATETIMEOFFSET value:
2019-09-19 10:01:01.000 -04:00
Next, convert that value to Pacific time by wrapping it in another AT TIME ZONE:
DECLARE #dte datetime = '20190919 10:01:01';
SELECT
(#dte AT TIME ZONE 'Eastern Standard Time') AT TIME ZONE 'Pacific Standard Time' AS datetime;
That returns another DATETIMEOFFSET:
2019-09-19 07:01:01.000 -07:00
Last but not least, for your presentation purposes, wrap that in a CAST so that you only get a DATETIME for your end users:
DECLARE #dte datetime = '20190919 10:01:01';
SELECT
CAST((#dte AT TIME ZONE 'Eastern Standard Time') AT TIME ZONE 'Pacific Standard Time' AS datetime);
Results:
2019-09-19 07:01:01.000
And Bob's your uncle.
Of course, if you want to take the lazy approach, DATEADD will get you where you want to be, too:
DECLARE #dte datetime = '20190919 10:01:01';
SELECT
DATEADD(HOUR, -3, #dte);
2019-09-19 07:01:01.000

SQL Server AT TIME ZONE

Using AT TIME ZONE is there a way to get my UTC Time without the 00:00 AT The end without using a LEFT in my query.
im doing this:
SELECT GETDATE() AT TIME ZONE 'EASTERN standard time' at time zone 'UTC'
Answer: 2018-03-05 15:08:00.930 +00:00
and trying to see if there is a better way other than doing
SELECT LEFT(GETDATE() AT TIME ZONE 'EASTERN standard time' at time zone 'UTC',23)
I would say declare it as variable and get datetime info from the datetimeoffset
Convert to datetime will do the trick
DECLARE #MyUtctime DATETIMEOFFSET
SET #MyUtctime = (
SELECT getdate() AT TIME ZONE 'EASTERN standard time' at TIME zone 'UTC'
)
SELECT CONVERT(DATETIME, #MyUtctime, 1)
SELECT getdate()
The following code will output your desired results:
CONVERT(VARCHAR, CONVERT(DATETIME, <DateField> AT TIME ZONE 'Eastern Standard Time' AT TIME ZONE 'UTC'), 100) AS [LocalDateTime]
If your EST date was '2018-03-22 22:48:24.893' the output UTC date would be 'Mar 22 2018 2:48AM'.

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.

How can I convert a Sql Server 2008 DateTimeOffset to a DateTime

I'm hoping to convert a table which has a DATETIMEOFFSET field, down to a DATETIME field BUT recalculates the time by taking notice of the offset. This, in effect, converts the value to UTC.
eg.
CreatedOn: 2008-12-19 17:30:09.0000000 +11:00
that will get converted to
CreatedOn: 2008-12-19 06:30:09.0000000
or
CreatedOn: 2008-12-19 06:30:09.0000000 + 00:00 -- that's a `DATETIMEOFFSET`, but `UTC`.
Cheers :)
Converting using almost any style will cause the datetime2 value to be converted to UTC.
Also, conversion from datetime2 to datetimeoffset simply sets the offset at +00:00, per the below, so it is a quick way to convert from Datetimeoffset(offset!=0) to Datetimeoffset(+00:00)
declare #createdon datetimeoffset
set #createdon = '2008-12-19 17:30:09.1234567 +11:00'
select CONVERT(datetime2, #createdon, 1)
--Output: 2008-12-19 06:30:09.12
select convert(datetimeoffset,CONVERT(datetime2, #createdon, 1))
--Output: 2008-12-19 06:30:09.1234567 +00:00
I'd use the built in SQL option:
select SWITCHOFFSET(cast('2008-12-19 17:30:09.0000000 +11:00' as datetimeoffset),'+00:00')
I know this is an old question but, if you want to convert DateTimeOffset to a DateTime, I think you need to take into account the timezone of the server you are converting on. If you just do a CONVERT(datetime, #MyDate, 1) you will simply lose the time zone, which likely results in an incorrect conversion.
I think you first need to switch the offset of the DateTimeOffset value, then do the conversion.
DECLARE #MyDate DATETIMEOFFSET = '2013-11-21 00:00:00.0000000 -00:00';
SELECT CONVERT(DATETIME, SWITCHOFFSET(#MyDate, DATEPART(tz,SYSDATETIMEOFFSET())));
The result of converting '2013-11-21 00:00:00.0000000 -00:00' to a DateTime on a server who's offset is -7:00 will be 2013-11-20 17:00:00.000. With the above logic it doesn't mater what the time zone of the server or the offset of the DateTime value, it will be converted to DateTime in the servers time zone.
I believe you need to do this because a DateTime value includes an assumption that the value is in the time zone of the server.
DateTimeoffset (Timezone) conversion in SQL Server.
SQL Server 2016 (13.x) and later
Exmample
Select GETUTCDATE()
Select Convert(DATETIME, GETUTCDATE() AT TIME ZONE 'UTC' AT TIME ZONE 'Central European Standard Time')
Select Convert(DATETIME, GETUTCDATE() AT TIME ZONE 'UTC' AT TIME ZONE 'India Standard Time')
Result will be
2020-08-18 08:22:21.640
2020-08-18 10:22:21.640
2020-08-18 13:52:21.640
Note: The timezone information is discarded in conversion if no style ("126" here) is specified. It might also be discarded in some of the other styles, I don't know -- in any case the following correctly adjusts for the TZ information. See CAST and CONVERT.
select convert(datetime, cast('2008-12-19 17:30:09.0000000 +11:00' as datetimeoffset), 126) as utc;
Happy SQL'ing.
Edit
Not sure if it matters but ... datetime Can't actually store that level of precision/accuracy. If the above is run the fractional seconds will be truncated to 3 digits (and accuracy is less than that). The same-same with datetime2 (and datetimeoffset(7)) produces a non-truncated value:
select convert(datetime2, cast('2008-12-19 17:30:09.1234567 +11:00' as datetimeoffset(7)), 126) as utc;
In order to account for daylight savings time, I used the following:
CONVERT(
DateTime,
SWITCHOFFSET(
CONVERT(
DateTimeOffset,
CONVERT(
DateTime,
[time_stamp_end_of_interval],
120
)
),
DATENAME(
TzOffset,
CONVERT(
DateTime,
[time_stamp_end_of_interval],
120
) AT TIME ZONE 'Pacific Standard Time'
)
)
)
AS GOOD_PST
Note: time_stamp_end_of_interval is a varchar