Can you make SQL Server datetimeoffset "nullable"? - sql

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.

Related

BigQuery: Convert DateTime in different time zone to UTC

I'm new to Big Query,
I want to convert the following date-time to UTC timezone.
DateTime format "2021-07-03T23:59:00+04:00[Asia/Dubai]" to UTC.
Thank you.
You just need to convert it to TIMESTAMP() without specifying any timezone (since it automatically sets the datetime at UTC) and then convert it back to DATETIME():
SELECT
your_datetime,
DATETIME(TIMESTAMP(your_datetime)) AS datetime_utc
FROM
<your_table>
OUTPUT:
your_datetime datetime_utc
------------------------- -------------------
2021-07-03T23:59:00+04:00 2021-07-03T19:59:00

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;

Convert timezone in Azure SQL Data Warehouse

I have a DATETIME column from the US/Pacific timezone, but it is not encoded as such. How can I convert this to UTC timezone in Azure SQL Data Warehouse?
The AT DATETIME T-SQL function seems like the closest fit, but it is not supported by Azure SQL Data Warehouse.
https://learn.microsoft.com/en-us/sql/t-sql/queries/at-time-zone-transact-sql
For example, one record has a DATETIME of 2013-04-02 08:02:47.000000. After conversion it should be 2013-04-02 15:02:47.000000.
Because my data were stored in 'US/Pacific' I used TODATETIMEOFFSET() to add the specific offset to the data. Once stored as a DATETIMEOFFSET type, it is treated as UTC time by the server but the timezone offset is still available.
SELECT TODATETIMEOFFSET(time_in_pt, '-08:00') as time_with_pt_timezone ...
https://learn.microsoft.com/en-us/sql/t-sql/functions/todatetimeoffset-transact-sql
it's a little hard to answer with no context, but i believe you could just cast or convert the column to whatever date/time type you desire. Accounting for the timezone is hard to say, yet again, with a lack of context.
Right now (in winter) we are in PST which is UTC – 8 hours. So converting your date 2013-04-02 08:02:47.000000 to UTC will be 2013-04-02 16:02:47.0000000 value.
declare #mydate datetime2 = '2013-04-02 08:02:47.000000'
select dateadd(hh, 8, #mydate) as utcdate

Oracle DateTime query with time zones

I have a SQL Builder library that direcltly uses ADO.NET. I have a means of creating a select query with a greater-than-or-equal operator, like:
select *
from book
where book.date_created >= {some date}
My issue is that {some date} is going to always be in the UTC time zone, but it's being compared to the book.date_created column which is a TIMESTAMP(6) WITH TIME ZONE column, which will not be in the UTC timezone.
I can execute the query, but my results are off becuaes of timezone comparisons. My query is for all books where the date_created >= x, but some of the results returned are not greater than x because after subtracting 5 hours for the time zone, they are now less than x. The IDataRecord DateTime fields returned are converted to UTC using DateTime.SpecifyKind()
Can I form my query such that it interprets book.date_created in the UTC timezone?
Note: While I'd love to change my Oracle DB columns to not specify timezones, changing table structures is not something I can do.
Edit:
Currently, {some date} is a SQL Parameter. It's backing datatype is a DateTime with UTC as the timezone. As a parameter, it is a TimestampWithTZ. The Value of the parameter is a DateTime with the kind specified as UTC as well.
Update:
The issue seems to be related to my results set from the IDataRecord. When I pull DateTimes off, I use DateTime.SpecifyKind() to put them in UTC mode. The problem is, the date times come out as DateTimeKind.Unspecified. When converting from Unspecified to UTC, it just drops the timezone and declares it is UTC without changing the underlying value. I'm not sure how to have the IDataRecord pull in the TimeZone value.
You need to use the FROM_TZ function that transforms a TIMESTAMP into a TIMESTAMP WITH TIME ZONE. For example, if you know that your variable is in UTC time (+0:00):
SELECT *
FROM book
WHERE date_created >= from_tz(<timestamp>, '+0:00');
Here's a sample script that shows the behaviour you describe (your local time zone should be set to +1:00):
CREATE TABLE t (tz TIMESTAMP(6) WITH TIME ZONE);
INSERT INTO t VALUES
(to_timestamp_tz('20000101 00:00:00 +1:00','yyyymmdd hh24:mi:ss tzh:tzm'));
INSERT INTO t VALUES
(to_timestamp_tz('20000101 00:00:00 -1:00','yyyymmdd hh24:mi:ss tzh:tzm'));
-- This will return two values instead of one
SELECT *
FROM t
WHERE tz >= to_timestamp('20000101 00:00:00', 'yyyymmdd hh24:mi:ss');
-- This query will return only one row
SELECT *
FROM t
WHERE tz >= from_tz (to_timestamp('20000101 00:00:00',
'yyyymmdd hh24:mi:ss'), '+0:00');
below links will help you.
Datetime Datatypes and Time Zone Support
TIMESTAMP WITH TIME ZONE Data Type
Write Time Zone Aware Code in Oracle
ORACLE timezone summary
Oracle Date and Time data types

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