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

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

Related

How can I add/subtract the offset value into datetime and return new datetime value in SQL?

I am new to SQL and I want to add/subtract the offset value into the DateTime and return new date.
Currently, I am using this
SELECT
GETUTCDATE() AS UTCDate,
GETUTCDATE() AT TIME ZONE 'Eastern Standard Time'
which returns these values:
Current Result : 2021-12-28 07:19:39.320 -05:00
Expected Result : 2021-12-28 02:19:39.320
How can I achieve this? Any help would be appreciated. Thanks
You can use DATEADD and DATEDIFF function:
SELECT GETUTCDATE() AS UTCDate, GETUTCDATE() AT TIME ZONE 'Eastern
Standard Time' ,
DATEADD(MINUTE, DATEDIFF(MINUTE ,GETUTCDATE(), GETUTCDATE() AT TIME ZONE
'Eastern Standard Time')*-1, GETUTCDATE())
GETUTCDATE() returns datetime type. You can use SYSDATETIMEOFFSET() instead to get datetimeoffset and convert it to a desired timezone.
SELECT
SYSDATETIMEOFFSET() AS UTCDate_with_timezone,
SYSDATETIMEOFFSET() AT TIME ZONE 'Eastern Standard Time';
When AT TIME ZONE operator is applied to datetime value it does not change the value, you just inform the system what is the timezone. And this timezone will be just appended to the value.

Calculate time at specific Timezone, from UTC Time

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;

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.

SQL Convert GETUTCDATE to nvarchar timezone like 'Eastern Standard Time'

I would like to convert a GETUTCDATE() call to a timezone using a timezone string like 'Eastern Standard Time' or any timezone string located in the registry under HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones. Is there a method to do that or am I venturing into SQLCLR territory?
Current suggestions I've seen:
print CONVERT(datetime2, DATEADD(HOUR, -4, GETUTCDATE()))
Output:
2015-09-08 15:22:50.5000000
I'd like to see this with DST working.
Is something like this possible?
print CONVERT(datetime2, DATEADD(HOUR, 'Eastern Standard Time', GETUTCDATE()))
I have SQL Server 2012 Standard available to me. Any suggestions? Thank you in advance!
You need to check out DATETIMEOFFSET datatype which is a datetime datatype that includes that timezone.
Also, there's a function called SWITCHOFFSET which allows you to switch a given DATETIMEOFFSET to another timezone.
With those two pieces, you can do:
DECLARE #CurrentDateTime DATETIMEOFFSET
SELECT #CurrentDateTime = SYSDATETIMEOFFSET()
DECLARE #OtherDateTime DATETIMEOFFSET
SELECT #OtherDateTime = SWITCHOFFSET(#CurrentDateTime, `-05:00')
You can use
SYSDATETIMEOFFSET() AT TIME ZONE 'Eastern Standard Time'
This returns datetime with offset in zone you specify. This can easly converted to datetime, datetime2

SQL Server DateTimeOffset matching same "day"

My application needs to collect "Tuesday's" purchases for all locations world wide, where "Tueday" is the location's Tuesday (regardless of time zone). And if the user needs to re-run the report next week, I need to still get "Last Tuesday's" data. All of our data is stored using DateTimeOffset.
So
9/4/12 00:00:00 -7 through 9/4/12 23:59:59 -7
must MATCH
9/4/12 00:00:00 +11 through 9/4/12 23:59:59 +11
when I am executing my WHERE clause.
I can't convert to UTC in the WHERE clause because that will pick up the data for "Tuesday" in London (depending on DST), not the location's Tuesday.
I tried converting from DateTimeOffset to DateTime, but that seems to convert to UTC. (In my tests, passing 9/1/12 through 9/30/12 picked up 8/31/12 data.)
Is there a trick to doing something like this with TSQL?
Thanks!
IMHO
DateTimeOffset = DateTime+Offset(from UTC)
So your data is already representing Client's Local date and time. Just cast it to DateTime and you will get the client's local Date and time.
But in-case if you want to add the Offset to the datetime and want the resultant Datetime then
DECLARE #PurchaseDate DATETIMEOFFSET(7) = CAST('2007-05-08 12:30:29.1234567 +5:00' AS datetimeoffset(7))
SELECT CAST(SWITCHOFFSET (#PurchaseDate , '+00:00') AS DATETIME)
have a look at this blog for further info.
http://blogs.msdn.com/b/bartd/archive/2009/03/31/the-death-of-datetime.aspx
When casting a DATETIMEOFFSET as DATETIME it takes the date and time as offset in the value and simply drops the time zone. The same is true when casting as DATE or TIME. So, I think you can simply cast the column as DATE and compare that to the date-only value you wish to match:
DECLARE #targetDate DATETIME2 = '2012-09-04' --Or we could use DATE here
SELECT [PurchaseId], [PurchaseTime], CAST([PurchaseTime] AS DATE) AS "PurchaseDate"
FROM [Purchases]
WHERE CAST([PurchaseTime] AS DATE) = #targetDate
I'm not sure how efficient this will be (hopefully not bad if the provider is truly clever--which SQL Server likely would be), but you might improve it by bounding the original column value as well:
DECLARE #targetDate DATETIME2 = '2012-09-04' --DATETIME2 so we can adjust by hours
SELECT [PurchaseId], [PurchaseTime], CAST([PurchaseTime] AS DATE) AS "PurchaseDate"
FROM [Purchases]
WHERE CAST([PurchaseTime] AS DATE) = #targetDate --Keep only the local-date matches
AND [PurchaseTime] >= DATEADD(hh, -14, #targetDate) --Up to 14-hour time zone offset
AND [PurchaseTime] <= DATEADD(hh, 38, #targetDate) --24 hours later plus 14
This should efficiently index down to the set of possibilities and then filter properly on the conversion to the local date. Note that time zone offsets can be up to 14 hours (New Zealand is furthest I know at +13:00, but they can go to +/- 14:00 according to MSDN) and the #targetDate will be at the start of the day, so it compares back to 14 hours earlier and 24+14=38 hours later. DATETIME2 has the same range and precision as DATETIMEOFFSET, so it's better for this purpose than the original DATETIME (but it may also work okay with DATETIME instead).