My database have date values saved in GMT time zone in int format. I am trying to convert the date to local timezone, but the issue arises when the date is a past date, For instance in my case offset for date Dec 1, 2012 will be -5 and for June 15, 2010 will be -4 due to daylight savings. I am currently in EST.
So i need to know what was the UTC date of a previous date to be able to determine whether -4 or -5 will be the offset for that date.
SELECT Test_Number,
Last_Test_Date, dateAdd(hour,
datediff(hour, GETUTCDATE(), getdate()), --UTC offset
dateadd(second, Last_Test_Date, '1/1/1970 12:00 AM'))
FROM TestTable
I am not entirely sure if it is even possible. Any opinion ?
It sounds like you are actually looking to convert a UTC time stored in the database to a local date/time with the correct offset (-5 or -4).
There is no good way to do this in SQL Server. At least, not yet.
The best advice I can offer is to not do this in conversion in the database. Instead, pass the UTC value as-is back to your application code, and do the conversion there.
For example, if your application is written in .NET, you can use TimeZoneInfo or Noda Time to handle the conversions to any time zone you wish. If you're using something else, let me know and I will update the question.
Related
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
We have data in SQL Server 2008, with multiple date time columns. As date format in SQL Server is a big integer value i.e. number of seconds since 1970, we are using DATEADD() function to convert it into actual date time format. But the issue we are facing is that when we use DATEADD(), we get data in UTC timezone whereas we want data in EST. I tried simply using -4 HR from the time but during NOV - MAR we are 1 HR ahead because the difference is 5 HR when daylight time is off. Is there any function that can be used which considers daylight saving time. Any help is appreciated.
Current Function -> DATEADD(s, columnName, '01/01/1970 00:00:00')
Regards, Sahil
try this:
DATEADD(mi, DATEDIFF(mi, GETUTCDATE(), GETDATE()), columnName)
You can use my SQL Server Time Zone Support project for this. It uses IANA standard time zone names, as listed here.
Building on your example, the following first converts from a UNIX Timestamp to a UTC based datetime, then converts to a datetime in the US Eastern time zone.
SELECT Tzdb.UtcToLocal(DATEADD(s, columnName, '1970-01-01 00:00:00'), 'America/New_York')
I would write a UDF that interacts with a time database such as the one from worldtimeserver.com -- I'm not affiliated with them and have found it with a quick internet search.
Further research shows timezonedb.com which has a free (if non-commercial) membership, allows to download the database and has examples on how to use with SQL Server and MySQL.
I have values stored as "datetime year to fraction (3)" in UTC which I'd like to offset to the timezone on my server. I'm trying to use the function DBINFO 'utc_to_datetime' to convert to local time, but the second argument is supposed to be an integer, and my values are in datetime. So, how would I convert a datetime to integer?
DBINFO('utc_to_datetime', …) isn't the correct tool
Using:
SELECT DBINFO('utc_to_datetime', 0)
FROM sysmaster:sysdual
yields:
1970-01-01 00:00:00
(at least, it does when the server's time zone is set via TZ=UTC0). Changing that to:
SELECT DBINFO('utc_to_datetime', 1506107444)
FROM sysmaster:sysdual
yields (with the same server running in UTC):
2017-09-22 19:10:44
Changing to the time zone on your server
There is some room to discuss the exact details, but basically what you need to do is add or subtract an INTERVAL representing the time zone to the DATETIME YEAR TO FRACTION(3) values.
For example:
DROP TABLE IF EXISTS datetime_values;
CREATE TABLE datetime_values
(
original DATETIME YEAR TO FRACTION(3) NOT NULL,
modified DATETIME YEAR TO FRACTION(3)
);
INSERT INTO datetime_values(original) VALUES('1970-01-01 00:00:00');
INSERT INTO datetime_values(original) VALUES('2017-09-22 12:31:46');
INSERT INTO datetime_values(original) VALUES('1066-10-21 14:20:04');
INSERT INTO datetime_values(original) VALUES('9989-01-20 00:00:00');
SELECT * FROM datetime_values;
UPDATE datetime_values
SET modified = original - INTERVAL(-5:30) HOUR TO MINUTE;
SELECT * FROM datetime_values;
When run, that gives:
1970-01-01 00:00:00.000
2017-09-22 12:31:46.000
1066-10-14 14:20:04.000
9989-01-20 00:00:00.000
1970-01-01 00:00:00.000 1970-01-01 05:30:00.000
2017-09-22 12:31:46.000 2017-09-22 18:01:46.000
1066-10-14 14:20:04.000 1066-10-14 19:50:04.000
9989-01-20 00:00:00.000 9989-01-20 05:30:00.000
There are multiple ways to represent the time zone offset. What's best may depend on what format you currently have it available in. If there's a table with the value in a column as an INTERVAL HOUR TO MINUTE value, that's probably easiest — it could be a temporary table created for the job. You can handle strings, or two integers (for hours and minutes), or one integer for hours (won't handle time zones for India (UTC+5:30), Nepal (UTC+5:45) or Newfoundland (UTC-4:30).
There's the interesting question of is a time zone offset east of UTC positive or negative: ISO 9945 says positive west, negative east; ISO 8601 (and ISO 9075, SQL) says positive east, negative west. Follow ISO 8601 by choice, but be aware of the issue.
Winter vs Summer Time — Daylight Saving vs Standard Time
My problem with interval is that we are sometimes on CST and sometimes CDT, ie. -6 hours and -5 hours. The server automatically updates its time, so I'd like to use that to my benefit. Can I dynamically choose the interval somehow?
This gets very tricky, very quickly. In some areas of the world, the rules about switching between winter and summer time (I'm going to use that term, though it isn't particularly standard, but then daylight saving isn't standard worldwide except to the extent US software has bludgeoned people into accepting it) change most years, sometimes on a political whim, sometimes because of interactions between observational lunar calendars and events such as Ramadan. The 'Olson Time Zone Database' is hosted by IANA at https://www.iana.org/time-zones (aka https://www.iana.org/tz; this redirects to the longer name). This year, the current release of the database is still 2017b; however, in years past, there were releases such as 2005r, 2006n, 2007k, 2008h, 2009r, 2010n, 2011i, 2012i, 2013i, 2014g, 2015g, 2016j — they're not necessarily the last release in those years, but they are the latest release I have for each of those years. I believe there will be (at least) one more release this year, somewhere close to the end of October. One problem is that there often isn't very much notice of the change of time zone rules.
Ignoring the issue of changing definitions of the switch between winter and summer time in some parts of the world, you have the problem of determining the time zone offset that the server uses. There is a DBINFO('get_tz') call that returns the server's time zone string; it does not, however, tell you the offset from UTC. You could retrieve that string and apply it locally (to code running in a client), but that is indubitably messy.
SELECT DBINFO('utc_current'), DBINFO('get_tz'),
CURRENT YEAR TO SECOND
FROM sysmaster:sysdual
At one point, I ran that query and got:
1506114539 UTC0 2017-09-22 21:08:59
Using GNU date, I could analyze that:
$ /opt/gnu/bin/date -u -d #1506114539
Fri Sep 22 21:08:59 UTC 2017
$ /opt/gnu/bin/date -d #1506114539
Fri Sep 22 14:08:59 PDT 2017
$
This shows that the number of seconds since 'The Epoch' was 1,506,114,539, which translates to 21:08:59 on 22nd September 2017 in the UTC (GMT, more or less) time zone. It was also 14:08:59 in the US/Pacific or America/Los_Angeles time zone, which has the abbreviation PDT (Pacific Daylight Time).
Determining that difference (7 hours during summer or daylight saving time) in the Informix server is tricky. Doubly so when dealing with times in the other time zone offset value, and ambiguously so when dealing with times in the hours between 01:00 and 02:00 on the morning when the clocks 'fall back' (there is no way to tell whether the time value was stored using the winter time zone offset or the summer time zone offset).
I'm going to need to meditate on this — and poke around previous answers, etc.
I have two questions regarding querying data in SQL that uses Epoch time stamps. I'm able to convert the date in my SELECT statement using this text:
DATEADD(HOUR, -4, DATEADD(SECOND, aa.fldTimeOfEvent, '1970-01-01 00:00:00'))
I had to use the "hour,-4" to convert it to Eastern daylight savings time. I'm curious if I will need to adjust this to -5 in November when daylight savings time ends? Is there a way to formulate the SELECT statement so it automatically adjusts for DST? This will be part of an automated report and I'm afraid we may miss changing this value.
Another question is how to use the WHERE statement to get data for a certain day. For instance, if I wanted the WHERE statement to grab all entries that occurred any time today (7/14/16), how would I do that? I've tried this statement:
WHERE DATEADD(HOUR, -4, DATEADD(SECOND, aa.fldTimeOfEvent, '1970-01-01 00:00:00')) = '2016-07-14'
It appears to only grab the entries that are exactly equal to midnight of that day (I think). I want all entries that occurred for any time the day.
Thanks in advance for your help.
The easy part first:
If you need to compare the date only, convert your datetimes to dates before comparing with: CONVERT(date, yourdatefield)
The second part has been discussed and solved here for UTC time: Convert Datetime column from UTC to local time in select statement. You would still need to add in the offset for Epochtime.
I'm assuming you're using SQL Server. If you only ever need the current offset, you can use GETUTCDATE() to calculate it:
SELECT DATEDIFF(hour,GetUTCDate(),GETDATE())
If you need to calculate the offset for other dates you'll likely want to use a CLR function: https://dba.stackexchange.com/questions/28187/how-can-i-get-the-correct-offset-between-utc-and-local-times-for-a-date-that-is
Which links to: https://blogs.msdn.microsoft.com/sqlserverfaq/2011/07/29/how-to-convert-utc-time-to-local-time-in-sql/
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).