I'm struggling with a SQL query - a basic select statement with a UTC time conversion in the select output. I've done a bunch of searching on this and through all of that have arrived at the following query, but it does not seem to work for me.
SELECT [Id]
,[BaseSource]
,[Source]
,[Output]
,[SessionId]
,[Timestamp]
,(SELECT DATEADD(MILLISECOND,DATEDIFF(MILLISECOND,getutcdate(),GETDATE()),[Timestamp])) as LocalTime
FROM [MYDB].[dbo].[SystemOutput]
ORDER BY [Timestamp] DESC
This line is where the magic should be happening, but instead i get a exact match of the Timestamp column value, so no conversion happening at all:
(SELECT
DATEADD(MILLISECOND,DATEDIFF(MILLISECOND,getutcdate(),GETDATE()),[Timestamp]))
Does anyone know of how to get this working?
Thanks
First, understand that getdate() returns the local date and time of the server - not of the person running the query. If the server's time zone is set to UTC, then it will indeed return the UTC time.
Since you are running on SQL 2016, and you are asking for the UTC time converted to Pacific time, I suggest you use the built-in AT TIME ZONE statement, as follows:
SELECT [Id]
,[BaseSource]
,[Source]
,[Output]
,[SessionId]
,[Timestamp]
,[Timestamp] AT TIME ZONE 'UTC' AT TIME ZONE 'Pacific Standard Time' AS LocalTime
FROM [MYDB].[dbo].[SystemOutput]
ORDER BY [Timestamp] DESC
Note, the above assumes that the [Timestamp] field is a datetime or datetime2, and that it is a UTC-based value. The first AT TIME ZONE makes an assertion that the given value is in UTC, resulting in a datetimeoffset. The second AT TIME ZONE then converts from UTC to Pacific time.
If instead the field is already a datetimeoffset type, then the query is even simpler:
SELECT [Id]
,[BaseSource]
,[Source]
,[Output]
,[SessionId]
,[Timestamp]
,[Timestamp] AT TIME ZONE 'Pacific Standard Time' AS LocalTime
FROM [MYDB].[dbo].[SystemOutput]
ORDER BY [Timestamp] DESC
Also, don't be confused by the word "Standard" in the time zone identifier. That value covers both standard time and daylight time, as applicable in the Pacific time zone in the US and Canada.
Related
How do I convert a column of type text to type date/time? I have the createdon column that I convert from UTC time to eastern time zone with day light savings time in consideration. This works. However, the createon column results in a type text. I need it in date and time.
Below is my SQL query. How exactly would you write the conversion within the existing query? This is for SQL Server. Thanks.
select [$Table].[field1] as [field1],
...,
[$Table].[createdon] at time zone 'UTC' at time zone 'Eastern Standard Time' as [createdon],
...,
[$Table].[fieldN] as [fieldN]
from [dbo].[TableA] as [$Table]
I was able to do the conversion by using the cast keyword and convert as a date type.
I am trying to offset the time in the column based on the time zone. I am trying to use this:
SELECT
SERIAL_NUMBER,
CONVERT(datetime, TIME_FROM)
AT TIME ZONE ('US Eastern Standard Time')
FROM
tmp_TestZone
which returns what I need, however each row in my table has record with specific time zone which can be any time zone. What I have to do is to replace 'US Eastern Standard Time' with a nested query that will pull the correct time zone for particular serial number. Time zone is stored in the last column which is TIMEZONE_LU.TZ
My table looks like this:
,[IP_ADDRESS]
,[NAME]
,[GROUP_NAME]
,[DEVICE_TYPE]
,[LINE_NAME]
,[DATE_FROM]
,[TIME_FROM]
,[TIME_TO]
,[fw]
,[bw]
,[SITE_NAME]
,[TZ]
I tried to build the query like this:
SELECT
SERIAL_NUMBER,
CONVERT(datetime, TIME_FROM)
AT TIME ZONE (SELECT TZ
FROM tmp_TestZone) NEW_TIME
FROM
tmp_TestZone
But I'm getting an error:
Msg 512, Level 16, State 1, Line 2
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
How do I fix this?
The suggestion:
SELECT
SERIAL_NUMBER,
CONVERT(datetime, TIME_FROM)
AT TIME ZONE (SELECT TZ
FROM tmp_TestZone) NEW_TIME
FROM
tmp_TestZone
Would work however i just found that my timezones are not standardized.
I am going to try to use
SELECT SERIAL_NUMBER,
SWITCHOFFSET(TIME_FROM, '-05:00')
FROM tmp_TestZone2
Could you help me to replace '-05:00' from above code so ti reads values from UTC_offset column which are in exact format as '-05:00'
Thank you so much
Ok so here is the table:
SELECT [SERIAL_NUMBER]
,[IP_ADDRESS]
,[NAME]
,[GROUP_NAME]
,[DEVICE_TYPE]
,[LINE_NAME]
,[DATE_FROM]
,[TIME_FROM]
,[TIME_TO]
,[fw]
,[bw]
,[SITE_NAME]
,[TZ]
,[CC]
,[UTC_offset]
,[UTC_DST_offset]
FROM [VHA].[dbo].[tmp_TestZone2]
And here is the data of that table:
I have the columns TIME_FROM and TIME_TO that needs to be offset for UTC_Offset values.
So for the instance in the picture TIME_FROM (10:10:00) and TIME_TO (11:00:00) should be offset for -7:00 and so on for every row the TIME_FROM and TIME_TO should be offset for what ever value is in column UTC_Offset.
Try like this
SELECT
SERIAL_NUMBER,
CONVERT(datetime, TIME_FROM)
AT TIME ZONE temp.tz
FROM
tmp_TestZone AS temp;
This may help you.
Edited Question's answer:
If I understood your question correctly then please try below query to remove your Time Offset from the result...
SELECT SERIAL_NUMBER,
CONVERT(varchar(19),SWITCHOFFSET(TIME_FROM, '-05:00'),120) AS Result_date
FROM tmp_TestZone2
OR
SELECT SERIAL_NUMBER,
CONVERT(varchar(19),SWITCHOFFSET(TIME_FROM, UTC_offset),120) AS Result_date
FROM tmp_TestZone2
Maintain varchar(19) length according your DATETIME CONVERSION CODE (like 120).
I have user created records that I am storing the create date in UTC in a sql database.
I want to allow the user to select a date on the UI that will pull the records for that day.
My local time is -4:00 from the UTC time. So here is my issue:
If a user created a record at 9:00AM local time (1:00PM UTC), and then another record at 10:00PM local time (2:00AM UTC the next day), how do I query both those records out when they select that day?
The records are stored in UTC so they fall in 2 separate days, but they are actually in the same day for the local time.
How would I solve this? Should I even be storing the records in UTC?
Thanks
Is the -4 hours difference always there, or do you have multiple users from different time zones? If first one applies, consider dateadd. For example:
SELECT dateadd(hour, -4, yourTimeStamp) as TimeStamp
, CAST(dateadd(hour, -4, yourTimeStamp) as DATE) as DateOfTimeStamp
FROM YourTable
WHERE CAST(dateadd(hour, -4, yourTimeStamp) as DATE) = '20160510'
EDIT:
You can use:
SELECT DATEDIFF(MINUTE, SYSDATETIME(), GETDATE()) AS MinutesOffsetUTCtoLocal
to get the time difference in minutes between the client and the machine. Integrating this would look like this:
SELECT dateadd(minute, DATEDIFF(MINUTE, SYSDATETIME(), GETDATE()), yourTimeStamp) as TimeStamp
, CAST(dateadd(minute, DATEDIFF(MINUTE, SYSDATETIME(), GETDATE()), yourTimeStamp) as DATE) as DateOfTimeStamp
FROM YourTable
WHERE CAST(dateadd(minute, DATEDIFF(MINUTE, SYSDATETIME(), GETDATE()), yourTimeStamp) as DATE) = '20160510'
I suggest to build a calendar table with the following columns (will be handy for other things too) - in my examples it is called: local_calendar
local_date DATE -- This marks the day (without time)
date_starts_utc DATETIME -- Local midnight converted to UTC
date_ends_utc DATETIME -- Local midnight of the next day converted to UTC.
Fill this table from and to a reasonable date range.
From now, you can join this table to any UTC time to get the local date and any local dates to utc time boundaries.
To get the local date for a utc time
SELECT local_date
FROM local_calendar
WHERE #utcTime >= date_starts_utc AND #utcTime < date_ends_utc
To get the UTC boundaries for a local date
SELECT #lowerBoundary = date_starts_utc, #higherBoundary = date_ends_utc
FROM local_calendar
WHERE date = #localDate
The scenario is this:
select max date from some table, when the target table having no data, so the max date is null. when the date being null, I want to get the earliest date of system, so the epoch time seems perfect.
I have searched some ways including DATEADD functions, but that seems not elegant.
If I understand your question correctly, in SQL Server the epoch is given by cast(0 as datetime) :
select Max(ISNULL(MyDateCol, cast(0 as datetime)))
from someTable
group by SomeCol
The earliest date that can be stored in a SQL datetime field depends on the data type you use:
datetime:
1753-01-01 through 9999-12-31
smalldatetime:
1900-01-01 through 2079-06-06
date, datetime2 and datetimeoffset:
0001-01-01 through 9999-12-31
For more exact details see from https://msdn.microsoft.com/en-GB/library/ms186724.aspx#DateandTimeDataTypes
The epoch is useful if you are converting numbers to dates, but irrelevant if you are storing dates as dates.
If you don't want to deal with nulls properly the simple answer is to pick a date that you know will be before your data and hard-code it into your query. cast('1900-01-01' as datetime) will work in most cases.
While using something like cast(0 as datetime) produces the same result it obscures what you have done in your code. Someone maintaining it, wondering where these odd old dates come from, will be able to spot the hard coded date more quickly.
If you define the epoch as Jan 1, 1970: The better: to store it in a variable
DECLARE #epoch DATETIME
SET #epoch = CONVERT( DATETIME, '01 JAN 1970', 106 )
select
DATEPART(YEAR, DATEADD(day, 180, #epoch)) as year,
...
I'm stuck. Need help.
I store UTC dates in database.
Example rows:
GeneratedAt:
2011-06-08 23:30
2011-06-09 03:30
2011-06-09 15:30
Local time for my user is -2 hours (Central Europe). When I want rows from 09 then I have 3 rows.
Problem is with GROUP BY day for reporting purposes. I have 1 for 08 and 2 for 09 but this is not true for my local time.
Everywhere I see: "store data in UTC". How to do this properly?
UPDATE 1:
For data access I'm using NHibernate and I prefer solution independent of the database engine. So, I'm looking for solution with something like Date/Time Dimension table (or something like that).
My data table has columns like this:
GeneratedAt (datetime)
GeneratedAt_Year (int)
GeneratedAt_Month (int)
GeneratedAt_Day (int)
GeneratedAt_Hour (int)
Thanks to that I can easily grouping by: year, year+month, year+month+day, year+month+day+hour. Unfortunately this is UTC. :(
How to refactor this solution to deal with user timezones?
You could create a view of that table which provides the datetime value in the desired Central Europe timezone by applying a DATEADD function.
So if your table columns are: id, other_id, evt_time
then the select statement (for the view definition) would be:
SELECT id, other_id, evt_time, DATEADD( hh, -2, evt_time ) AS evt_time_ce
FROM MyTable
then you can use the view and apply the GROUP_BY to the evt_time_ce column
I have a similar issue in general, but my time difference is 8 hours.
I use dateadd(hour,8, [Timestamp]) to select the local time, and dateadd(hour,-8, #dateFrom) in WHERE clauses - which should work for GROUP BY as well.
For example:
DECLARE #dateFrom datetime, #dateUntil datetime
SET #dateFrom = '2011-06-20 00:00:02.000'
SET #dateUntil = '2011-06-22 10:00:00.000'
SELECT TOP 100
dateadd(hour, 8, [Timestamp]) LocalTime,
*
FROM [Log] L (nolock)
WHERE L.[Timestamp] BETWEEN dateadd(hour, -8, #dateFrom) AND dateadd(hour, -8, #dateUntil)
ORDER BY LogID DESC
SQL Server 2016 has introduced AT TIME ZONE that can help with this, including handling daylight savings time.
AT TIME ZONE lets you convert dates between time zones listed in the windows registry. You can see what timezones are available by running a simple SELECT:
select * from sys.time_zone_info
Here's the SQL that converts your UTC stored date into a date at another timezone
GeneratedAt
AT TIME ZONE 'UTC'
AT TIME ZONE 'Central Europe Standard Time'
So your SQL to group by day based on a local timezone might look something like this:
SELECT DATEADD(DAY,0, DATEDIFF(DAY, 0, GeneratedAt
AT TIME ZONE 'UTC'
AT TIME ZONE 'Central Europe Standard Time'))
FROM YourTable
GROUP BY DATEADD(DAY,0, DATEDIFF(DAY, 0, GeneratedAt
AT TIME ZONE 'UTC'
AT TIME ZONE 'Central Europe Standard Time'))
Here's a good article about the topic if you want to read more.