I'm working on a SQL query which returns a integer which is the number of minutes between two given dates as follows
DATEDIFF(mi, date_one, getdate())
The above query returns difference in two dates in minutes but for getdate() I would want to supply my own time.
For example, consider
date_one= 2015-12-29 13:39:03.000
getdate() return current date and time ie., 2015-12-29 14:33:50.000
But, I want to change time part in getdate() to some 10:00:00.00 so that the getdate() is 2015-12-29 10:00:00.00 by passing an hour integer say 10.
May I know a good way to do that?
This will use getDate, but let you set your own hour. Just replace that second parameter (which is 10 with whichever hour you want). Use this expression in place of getDate() in your dateDiff function.
DATEADD(hh, 10, DATEADD(d, DATEDIFF(d, 0, getDate()), 0))
You can also add minutes, seconds, milliseconds, etc. to get what you need.
Here I am adding 633 minutes to make it 10:33 (change the first parameter to mi for minutes).
select DATEADD(mi, 633, DATEADD(d, DATEDIFF(d, 0, getDate()), 0))
See the documentation for other value for the first parameter: https://msdn.microsoft.com/en-us/library/ms186819.aspx
Here is how to use it:
DATEDIFF(mi, getDate(),
DATEADD(mi, 633, DATEADD(d, DATEDIFF(d, 0, getDate()), 0))
)
This will give you the minutes from the current time to 10:33 on the current day. Here is a sqlfiddle: http://sqlfiddle.com/#!6/9eecb7/5407
I find this function useful:
CREATE FUNCTION [dbo].[StripTimeFromDateTime]
(
#date DateTime
)
RETURNS DateTime
AS
BEGIN
RETURN DATEADD(dd, DATEDIFF(dd, 0, #date), 0)
END
This will knock the time off a datetime leaving it at 00:00:00.000. Then you can:
SELECT DATEADD(hour, 10, dbo.StripTimeFromDateTime(GetDate()))
Notice the example below:
select
cast('2015-12-28 12:15:00' as datetime),
getdate(),
cast(cast(convert(date, getdate()) as varchar(20)) + ' 10:00:00' as datetime);
|----------------------------|----------------------------|----------------------------|
| December, 28 2015 12:15:00 | December, 29 2015 20:42:35 | December, 29 2015 10:00:00 |
An example like the one you used:
with example as (
select cast('2015-12-28 12:15:00' as datetime) as date_one
)
select
date_one,
cast(cast(convert(date, getdate()) as varchar(20)) + ' 10:00:00' as datetime) as myown,
datediff(
mi,
date_one,
cast(cast(convert(date, getdate()) as varchar(20)) + ' 10:00:00' as datetime)
) as minutes
from example;
Result:
| date_one | myown | minutes |
|----------------------------|----------------------------|---------|
| December, 28 2015 12:15:00 | December, 29 2015 10:00:00 | 1305 |
Example on SQLFiddle: http://sqlfiddle.com/#!3/9eecb7/6599
The reason I used varchar is to have flexibility of typing a time such as '10:15:00' or other variations of time.
This one-liner will gives the current date with the time part replaced with the constant you want
select cast(cast(getdate() as date) as datetime) + cast(cast('10:00:00' as time) as datetime)
How this works:
Cast the getdate() result to date and then back to datetime to get the current date without the time.
select cast(cast(getdate() as date) as datetime)
Cast '10:00:00' to time and then to datetime to get 10:00:00 as datetime.
select cast(cast('10:00:00' as time) as datetime)
Add the two
select cast(cast(getdate() as date) as datetime) + cast(cast('10:00:00' as time) as datetime)
That's all
select DATEADD (hh,10, CONVERT(Datetime, CONVERT (date, GETDATE())))
First remove time and then add 10 hours.
I'm trying to query our database to find all records that were created between 6am yesterday and 6am today. This will be run in a report at any point during the day so set times/dates are useless.
I have this so far:-
SELECT * FROM DaySummaryDetail DSD
WHERE DSD.FromDateTime BETWEEN DATEADD(DAY, -1, GetDate())
AND DATEADD(Day, 1, GetDate())
But obviously this only works for 24 hours ago from right now until right now. I can't figure out how to apply a time as well as date.
Every example I find online seems slightly different and uses set dates/times ie, >= 20/02/2015 06:00:00.
I normally use Oracle SQL which would simply work using this:-
ptt.mod_date_time >= TRUNC (SYSDATE - 1) - 2 / 24
AND ptt.mod_date_time <= TRUNC (SYSDATE - 1) + 22 / 24
This would return results from 10pm to 10pm but the format appears totally different in SQL Server.
You can get the datetime values you are after by doing the following:
SELECT DATEADD(HOUR,6,CONVERT(DATETIME, CONVERT(DATE ,GETDATE()))) Today6AM,
DATEADD(HOUR,-18,CONVERT(DATETIME, CONVERT(DATE ,GETDATE()))) Yesterday6AM
By doing this: CONVERT(DATE ,GETDATE()) you are stripping off the time portion of today's date. Converting it back to datetime gives you midnight for today.
The query adds 6 hours to midnight of the current day for 6am today and subtracts 18 hours from midnight of the current day to give you 6am on the previous day.
Output:
Today6AM Yesterday6AM
================================================
2015-02-20 06:00:00.000 2015-02-19 06:00:00.000
So adding that to your query:
SELECT *
FROM DaySummaryDetail DSD
WHERE DSD.FromDateTime
BETWEEN DATEADD(HOUR,-18,CONVERT(DATETIME, CONVERT(DATE ,GETDATE())))
AND DATEADD(HOUR,6,CONVERT(DATETIME, CONVERT(DATE ,GETDATE())))
DECLARE #StartTimestamp datetime
DECLARE #EndTimestamp datetime
DECLARE #HourPartOfSearchRange nvarchar(6)
SET #HourPartOfSearchRange = ' 06:30'
SET #StartTimestamp =
CAST((CONVERT(varchar(11), DATEADD(DAY,-1,#CurrentUTCDateTime), 106) + #HourPartOfSearchRange) AS datetime)
SET #EndTimestamp =
CAST((CONVERT(varchar(11), #CurrentUTCDateTime, 106) + #HourPartOfSearchRange) AS datetime)
SELECT * FROM dbo.Test Where Timestamp Between #StartTimestamp AND #EndTimestamp
today 6am is
dateadd(hour,6,cast(cast(getdate() as date) as datetime))
cast(getdate() as date) truncates the timepart, cast it back as datetime because dateadd won't add hours otherwise and add 6hours
One solution would be like so:
select *
from DaySummaryDetail DSD
where DSD.FromDateTime between cast(cast(cast(getdate()-1 as date) as varchar(30)) + ' 06:00:00.000' as datetime)
and cast(cast(cast(getdate() as date) as varchar(30)) + ' 06:00:00.000' as datetime)
This should help ...
SELECT DATEADD( hour, 6, CAST(CAST(GETDATE(), AS Date) AS DateTime) ) AS 'Today#6am'
SELECT DATEADD( hour, 6, CAST(CAST(GETDATE()-1, AS Date) AS DateTime) ) AS 'Yesterday#6am'
In SQL Server 2012 you can use SMALLDATETIMEFROMPARTS to construct a datetime value that is today at 6am like this:
SMALLDATETIMEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), DAY(GETDATE()), 6, 0)
Output: 2015-02-20 06:00:00
then you can use the above expression in place of GETDATE() in the WHERE clause:
DECLARE #TodayAt6AM DATETIME = SMALLDATETIMEFROMPARTS(YEAR(GETDATE()),
MONTH(GETDATE()),
DAY(GETDATE()),
6,
0)
SELECT *
FROM DaySummaryDetail DSD
WHERE DSD.FromDateTime BETWEEN DATEADD(DAY, -1, #TodayAt6AM) AND
DATEADD(Day, 1, #TodayAt6AM)
I have recently updated my system to record date/times as UTC as previously they were storing as local time.
I now need to convert all the local stored date/times to UTC. I was wondering if there is any built in function, similar to .NET's ConvertTime method?
I am trying to avoid having to write a utility app to do this for me.
Any suggestions?
I do not believe the above code will work. The reason is that it depends upon the difference between the current date in local and UTC times. For example, here in California we are now in PDT (Pacific Daylight Time); the difference between this time and UTC is 7 hours. The code provided will, if run now, add 7 hours to every date which is desired to be converted. But if a historical stored date, or a date in the future, is converted, and that date is not during daylight savings time, it will still add 7, when the correct offset is 8. Bottom line: you cannot convert date/times properly between time zones (including UTC, which does not obey daylight savings time) by only looking at the current date. You must consider the date itself that you are converting, as to whether daylight time was in force on that date. Furthermore, the dates at which daylight and standard times change themselves have changed (George Bush changed the dates during his administration for the USA!). In other words, any solution which even references getdate() or getutcdate() does not work. It must parse the actual date to be converted.
With SQL Server 2016, there is now built-in support for time zones with the AT TIME ZONE statement. You can chain these to do conversions:
SELECT YourOriginalDateTime AT TIME ZONE 'Pacific Standard Time' AT TIME ZONE 'UTC'
Or, this would work as well:
SELECT SWITCHOFFSET(YourOriginalDateTime AT TIME ZONE 'Pacific Standard Time', '+00:00')
Either of these will interpret the input in Pacific time, properly account for whether or not DST is in effect, and then convert to UTC. The result will be a datetimeoffset with a zero offset.
More examples in the CTP announcement.
If they're all local to you, then here's the offset:
SELECT GETDATE() AS CurrentTime, GETUTCDATE() AS UTCTime
and you should be able to update all the data using:
UPDATE SomeTable
SET DateTimeStamp = DATEADD(hh, DATEDIFF(hh, GETDATE(), GETUTCDATE()), DateTimeStamp)
Would that work, or am I missing another angle of this problem?
As mentioned here previously, there is no build-in way to perform time zone rules aware date conversion in SQL Server (at least as of SQL Server 2012).
You have essentially three choices to do this right:
Perform the conversion outside of SQL Server and store results in the database
Introduce time zone offset rules in a standalone table and create stored procedures or UDFs to reference the rules table to perform conversions. You can find one take on this approach over at SQL Server Central (registration required)
You can create a SQL CLR UDF; I will describe the approach here
While SQL Server does not offer tools to perform time zone rules aware date conversion, the .NET framework does, and as long as you can use SQL CLR, you can take advantage of that.
In Visual Studio 2012, make sure you have the data tools installed (otherwise, SQL Server project won't show up as an option), and create a new SQL Server project.
Then, add a new SQL CLR C# User Defined Function, call it "ConvertToUtc". VS will generate boiler plate for you that should look something like this:
public partial class UserDefinedFunctions
{
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString ConvertToUtc()
{
// Put your code here
return new SqlString (string.Empty);
}
}
We want to make several changes here. For one, we want to return a SqlDateTime rather than a SqlString. Secondly, we want to do something useful. :)
Your revised code should look like this:
public partial class UserDefinedFunctions
{
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlDateTime ConvertToUtc(SqlDateTime sqlLocalDate)
{
// convert to UTC and use explicit conversion
// to return a SqlDateTime
return TimeZone.CurrentTimeZone.ToUniversalTime(sqlLocalDate.Value);
}
}
At this point, we are ready to try it out. The simplest way is to use the built-in Publish facility in Visual Studio. Right-click on the database project and select "Publish". Set up your database connection and name, and then either click "Publish" to push the code into the database or click "Generate Script" if you'd like to store the script for posterity (or to push the bits into production).
Once you have the UDF in the database, you can see it in action:
declare #dt as datetime
set #dt = '12/1/2013 1:00 pm'
select dbo.ConvertToUtc(#dt)
Here is a tested procedure that upgraded my database from local to utc time. The only input required to upgrade a database is to enter the number of minutes local time is offset from utc time into #Offset and if the timezone is subject to daylight savings adjustments by setting #ApplyDaylightSavings.
For example, US Central Time would enter #Offset=-360 and #ApplyDaylightSavings=1 for 6 hours and yes apply daylight savings adjustment.
Supporting Database Function
CREATE FUNCTION [dbo].[GetUtcDateTime](#LocalDateTime DATETIME, #Offset smallint, #ApplyDaylightSavings bit)
RETURNS DATETIME AS BEGIN
--====================================================
--Calculate the Offset Datetime
--====================================================
DECLARE #UtcDateTime AS DATETIME
SET #UtcDateTime = DATEADD(MINUTE, #Offset * -1, #LocalDateTime)
IF #ApplyDaylightSavings = 0 RETURN #UtcDateTime;
--====================================================
--Calculate the DST Offset for the UDT Datetime
--====================================================
DECLARE #Year as SMALLINT
DECLARE #DSTStartDate AS DATETIME
DECLARE #DSTEndDate AS DATETIME
--Get Year
SET #Year = YEAR(#LocalDateTime)
--Get First Possible DST StartDay
IF (#Year > 2006) SET #DSTStartDate = CAST(#Year AS CHAR(4)) + '-03-08 02:00:00'
ELSE SET #DSTStartDate = CAST(#Year AS CHAR(4)) + '-04-01 02:00:00'
--Get DST StartDate
WHILE (DATENAME(dw, #DSTStartDate) <> 'sunday') SET #DSTStartDate = DATEADD(day, 1,#DSTStartDate)
--Get First Possible DST EndDate
IF (#Year > 2006) SET #DSTEndDate = CAST(#Year AS CHAR(4)) + '-11-01 02:00:00'
ELSE SET #DSTEndDate = CAST(#Year AS CHAR(4)) + '-10-25 02:00:00'
--Get DST EndDate
WHILE (DATENAME(dw, #DSTEndDate) <> 'sunday') SET #DSTEndDate = DATEADD(day,1,#DSTEndDate)
--Finally add the DST Offset if needed
RETURN CASE WHEN #LocalDateTime BETWEEN #DSTStartDate AND #DSTEndDate THEN
DATEADD(MINUTE, -60, #UtcDateTime)
ELSE
#UtcDateTime
END
END
GO
Upgrade Script
Make a backup before running this script!
Set #Offset & #ApplyDaylightSavings
Only run once!
begin try
begin transaction;
declare #sql nvarchar(max), #Offset smallint, #ApplyDaylightSavings bit;
set #Offset = -360; --US Central Time, -300 for US Eastern Time, -480 for US West Coast
set #ApplyDaylightSavings = 1; --1 for most US time zones except Arizona which doesn't observer daylight savings, 0 for most time zones outside the US
declare rs cursor for
select 'update [' + a.TABLE_SCHEMA + '].[' + a.TABLE_NAME + '] set [' + a.COLUMN_NAME + '] = dbo.GetUtcDateTime([' + a.COLUMN_NAME + '], ' + cast(#Offset as nvarchar) + ', ' + cast(#ApplyDaylightSavings as nvarchar) + ') ;'
from INFORMATION_SCHEMA.COLUMNS a
inner join INFORMATION_SCHEMA.TABLES b on a.TABLE_SCHEMA = b.TABLE_SCHEMA and a.TABLE_NAME = b.TABLE_NAME
where a.DATA_TYPE = 'datetime' and b.TABLE_TYPE = 'BASE TABLE' ;
open rs;
fetch next from rs into #sql;
while ##FETCH_STATUS = 0 begin
exec sp_executesql #sql;
print #sql;
fetch next from rs into #sql;
end
close rs;
deallocate rs;
commit transaction;
end try
begin catch
close rs;
deallocate rs;
declare #ErrorMessage nvarchar(max), #ErrorSeverity int, #ErrorState int;
select #ErrorMessage = ERROR_MESSAGE() + ' Line ' + cast(ERROR_LINE() as nvarchar(5)), #ErrorSeverity = ERROR_SEVERITY(), #ErrorState = ERROR_STATE();
rollback transaction;
raiserror (#ErrorMessage, #ErrorSeverity, #ErrorState);
end catch
If you have to convert dates other than today to different timezones you have to deal with daylight savings. I wanted a solution that could be done without worrying about database version, without using stored functions and something that could easily be ported to Oracle.
I think Warren is on the right track with getting the correct dates for daylight time, but to make it more useful for multiple time zone and different rules for countries and even the rule that changed in the US between 2006 and 2007, here a variation on the above solution. Notice that this not only has us time zones, but also central Europe. Central Europe follow the last sunday of april and last sunday of october. You will also notice that the US in 2006 follows the old first sunday in april, last sunday in october rule.
This SQL code may look a little ugly, but just copy and paste it into SQL Server and try it. Notice there are 3 section for years, timezones and rules. If you want another year, just add it to the year union. Same for another time zone or rule.
select yr, zone, standard, daylight, rulename, strule, edrule, yrstart, yrend,
dateadd(day, (stdowref + stweekadd), stmonthref) dstlow,
dateadd(day, (eddowref + edweekadd), edmonthref) dsthigh
from (
select yrs.yr, z.zone, z.standard, z.daylight, z.rulename, r.strule, r.edrule,
yrs.yr + '-01-01 00:00:00' yrstart,
yrs.yr + '-12-31 23:59:59' yrend,
yrs.yr + r.stdtpart + ' ' + r.cngtime stmonthref,
yrs.yr + r.eddtpart + ' ' + r.cngtime edmonthref,
case when r.strule in ('1', '2', '3') then case when datepart(dw, yrs.yr + r.stdtpart) = '1' then 0 else 8 - datepart(dw, yrs.yr + r.stdtpart) end
else (datepart(dw, yrs.yr + r.stdtpart) - 1) * -1 end stdowref,
case when r.edrule in ('1', '2', '3') then case when datepart(dw, yrs.yr + r.eddtpart) = '1' then 0 else 8 - datepart(dw, yrs.yr + r.eddtpart) end
else (datepart(dw, yrs.yr + r.eddtpart) - 1) * -1 end eddowref,
datename(dw, yrs.yr + r.stdtpart) stdow,
datename(dw, yrs.yr + r.eddtpart) eddow,
case when r.strule in ('1', '2', '3') then (7 * CAST(r.strule AS Integer)) - 7 else 0 end stweekadd,
case when r.edrule in ('1', '2', '3') then (7 * CAST(r.edrule AS Integer)) - 7 else 0 end edweekadd
from (
select '2005' yr union select '2006' yr -- old us rules
UNION select '2007' yr UNION select '2008' yr UNION select '2009' yr UNION select '2010' yr UNION select '2011' yr
UNION select '2012' yr UNION select '2013' yr UNION select '2014' yr UNION select '2015' yr UNION select '2016' yr
UNION select '2017' yr UNION select '2018' yr UNION select '2019' yr UNION select '2020' yr UNION select '2021' yr
UNION select '2022' yr UNION select '2023' yr UNION select '2024' yr UNION select '2025' yr UNION select '2026' yr
) yrs
cross join (
SELECT 'ET' zone, '-05:00' standard, '-04:00' daylight, 'US' rulename
UNION SELECT 'CT' zone, '-06:00' standard, '-05:00' daylight, 'US' rulename
UNION SELECT 'MT' zone, '-07:00' standard, '-06:00' daylight, 'US' rulename
UNION SELECT 'PT' zone, '-08:00' standard, '-07:00' daylight, 'US' rulename
UNION SELECT 'CET' zone, '+01:00' standard, '+02:00' daylight, 'EU' rulename
) z
join (
SELECT 'US' rulename, '2' strule, '-03-01' stdtpart, '1' edrule, '-11-01' eddtpart, 2007 firstyr, 2099 lastyr, '02:00:00' cngtime
UNION SELECT 'US' rulename, '1' strule, '-04-01' stdtpart, 'L' edrule, '-10-31' eddtpart, 1900 firstyr, 2006 lastyr, '02:00:00' cngtime
UNION SELECT 'EU' rulename, 'L' strule, '-03-31' stdtpart, 'L' edrule, '-10-31' eddtpart, 1900 firstyr, 2099 lastyr, '01:00:00' cngtime
) r on r.rulename = z.rulename
and datepart(year, yrs.yr) between firstyr and lastyr
) dstdates
For the rules, use 1, 2, 3 or L for first, second, third or last sunday. The date part gives the month and depending on the rule, the first day of the month or the last day of the month for rule type L.
I put the above query into a view. Now, anytime I want a date with the time zone offset or converted to UTC time, I just join to this view and select get the date in the date format. Instead of datetime, I converted these to datetimeoffset.
select createdon, dst.zone
, case when createdon >= dstlow and createdon < dsthigh then dst.daylight else dst.standard end pacificoffsettime
, TODATETIMEOFFSET(createdon, case when createdon >= dstlow and createdon < dsthigh then dst.daylight else dst.standard end) pacifictime
, SWITCHOFFSET(TODATETIMEOFFSET(createdon, case when createdon >= dstlow and createdon < dsthigh then dst.daylight else dst.standard end), '+00:00') utctime
from (select '2014-01-01 12:00:00' createdon union select '2014-06-01 12:00:00' createdon) photos
left join US_DAYLIGHT_DATES dst on createdon between yrstart and yrend and zone = 'PT'
Here's my quick and dirty version. I know all of my dates were using the US Eastern time zone. You can change the offset or otherwise make it smarter as you need to. I was doing a one-time migration so this was Good Enough.
CREATE FUNCTION [dbo].[ConvertToUtc]
(
#date datetime
)
RETURNS DATETIME
AS
BEGIN
-- Declare the return variable here
DECLARE #utcDate datetime;
DECLARE #offset int;
SET #offset = (SELECT CASE WHEN
#date BETWEEN '1987-04-05 02:00 AM' AND '1987-10-25 02:00 AM'
OR #date BETWEEN '1988-04-03 02:00 AM' AND '1988-10-30 02:00 AM'
OR #date BETWEEN '1989-04-02 02:00 AM' AND '1989-10-29 02:00 AM'
OR #date BETWEEN '1990-04-01 02:00 AM' AND '1990-10-28 02:00 AM'
OR #date BETWEEN '1991-04-07 02:00 AM' AND '1991-10-27 02:00 AM'
OR #date BETWEEN '1992-04-05 02:00 AM' AND '1992-10-25 02:00 AM'
OR #date BETWEEN '1993-04-04 02:00 AM' AND '1993-10-31 02:00 AM'
OR #date BETWEEN '1994-04-03 02:00 AM' AND '1994-10-30 02:00 AM'
OR #date BETWEEN '1995-04-02 02:00 AM' AND '1995-10-29 02:00 AM'
OR #date BETWEEN '1996-04-07 02:00 AM' AND '1996-10-27 02:00 AM'
OR #date BETWEEN '1997-04-06 02:00 AM' AND '1997-10-26 02:00 AM'
OR #date BETWEEN '1998-04-05 02:00 AM' AND '1998-10-25 02:00 AM'
OR #date BETWEEN '1999-04-04 02:00 AM' AND '1999-10-31 02:00 AM'
OR #date BETWEEN '2000-04-02 02:00 AM' AND '2000-10-29 02:00 AM'
OR #date BETWEEN '2001-04-01 02:00 AM' AND '2001-10-28 02:00 AM'
OR #date BETWEEN '2002-04-07 02:00 AM' AND '2002-10-27 02:00 AM'
OR #date BETWEEN '2003-04-06 02:00 AM' AND '2003-10-26 02:00 AM'
OR #date BETWEEN '2004-04-04 02:00 AM' AND '2004-10-31 02:00 AM'
OR #date BETWEEN '2005-04-03 02:00 AM' AND '2005-10-30 02:00 AM'
OR #date BETWEEN '2006-04-02 02:00 AM' AND '2006-10-29 02:00 AM'
OR #date BETWEEN '2007-03-11 02:00 AM' AND '2007-11-04 02:00 AM'
OR #date BETWEEN '2008-03-09 02:00 AM' AND '2008-11-02 02:00 AM'
OR #date BETWEEN '2009-03-08 02:00 AM' AND '2009-11-01 02:00 AM'
OR #date BETWEEN '2010-03-14 02:00 AM' AND '2010-11-07 02:00 AM'
OR #date BETWEEN '2011-03-13 02:00 AM' AND '2011-11-06 02:00 AM'
OR #date BETWEEN '2012-03-11 02:00 AM' AND '2012-11-04 02:00 AM'
OR #date BETWEEN '2013-03-10 02:00 AM' AND '2013-11-03 02:00 AM'
OR #date BETWEEN '2014-03-09 02:00 AM' AND '2014-11-02 02:00 AM'
OR #date BETWEEN '2015-03-08 02:00 AM' AND '2015-11-01 02:00 AM'
OR #date BETWEEN '2016-03-13 02:00 AM' AND '2016-11-06 02:00 AM'
OR #date BETWEEN '2017-03-12 02:00 AM' AND '2017-11-05 02:00 AM'
OR #date BETWEEN '2018-03-11 02:00 AM' AND '2018-11-04 02:00 AM'
OR #date BETWEEN '2019-03-10 02:00 AM' AND '2019-11-03 02:00 AM'
OR #date BETWEEN '2020-03-08 02:00 AM' AND '2020-11-01 02:00 AM'
OR #date BETWEEN '2021-03-14 02:00 AM' AND '2021-11-07 02:00 AM'
THEN 4
ELSE 5 END);
SELECT #utcDate = DATEADD(hh, #offset, #date)
RETURN #utcDate;
END
The following should work as it calculates difference between DATE and UTCDATE for the server you are running and uses that offset to calculate the UTC equivalent of any date you pass to it. In my example, I am trying to convert UTC equivalent for '1-nov-2012 06:00' in Adelaide, Australia where UTC offset is -630 minutes, which when added to any date will result in UTC equivalent of any local date.
select DATEADD(MINUTE, DATEDIFF(MINUTE, GETDATE(), GETUTCDATE()), '1-nov-2012 06:00')
Unless I missed something above (possible), all of the methods above are flawed in that they don't take the overlap when switching from daylight savings (say EDT) to standard time (say EST) into account. A (very verbose) example:
[1] EDT 2016-11-06 00:59 - UTC 2016-11-06 04:59
[2] EDT 2016-11-06 01:00 - UTC 2016-11-06 05:00
[3] EDT 2016-11-06 01:30 - UTC 2016-11-06 05:30
[4] EDT 2016-11-06 01:59 - UTC 2016-11-06 05:59
[5] EST 2016-11-06 01:00 - UTC 2016-11-06 06:00
[6] EST 2016-11-06 01:30 - UTC 2016-11-06 06:30
[7] EST 2016-11-06 01:59 - UTC 2016-11-06 06:59
[8] EST 2016-11-06 02:00 - UTC 2016-11-06 07:00
Simple hour offsets based on date and time won't cut it. If you don't know if the local time was recorded in EDT or EST between 01:00 and 01:59, you won't have a clue! Let's use 01:30 for example: if you find later times in the range 01:31 through 01:59 BEFORE it, you won't know if the 01:30 you're looking at is [3 or [6. In this case, you can get the correct UTC time with a bit of coding be looking at previous entries (not fun in SQL), and this is the BEST case...
Say you have the following local times recorded, and didn't dedicate a bit to indicate EDT or EST:
UTC time UTC time UTC time
if [2] and [3] if [2] and [3] if [2] before
local time before switch after switch and [3] after
[1] 2016-11-06 00:43 04:43 04:43 04:43
[2] 2016-11-06 01:15 05:15 06:15 05:15
[3] 2016-11-06 01:45 05:45 06:45 06:45
[4] 2016-11-06 03:25 07:25 07:25 07:25
Times [2] and [3] may be in the 5 AM timeframe, the 6 AM timeframe, or one in the 5 AM and the other in the 6 AM timeframe . . . In other words: you are hosed, and must throw out all readings between 01:00:00 and 01:59:59. In this circumstance, there is absolutely no way to resolve the actual UTC time!
Depending on how far back you need to go, you can build a table of daylight savings times and then join the table and do a dst-sensitive conversion. This particular one converts from EST to GMT (i.e. uses offsets of 5 and 4).
select createdon, dateadd(hour, case when dstlow is null then 5 else 4 end, createdon) as gmt
from photos
left outer join (
SELECT {ts '2009-03-08 02:00:00'} as dstlow, {ts '2009-11-01 02:00:00'} as dsthigh
UNION ALL SELECT {ts '2010-03-14 02:00:00'} as dstlow, {ts '2010-11-07 02:00:00'} as dsthigh
UNION ALL SELECT {ts '2011-03-13 02:00:00'} as dstlow, {ts '2011-11-06 02:00:00'} as dsthigh
UNION ALL SELECT {ts '2012-03-11 02:00:00'} as dstlow, {ts '2012-11-04 02:00:00'} as dsthigh
UNION ALL SELECT {ts '2013-03-10 02:00:00'} as dstlow, {ts '2013-11-03 02:00:00'} as dsthigh
UNION ALL SELECT {ts '2014-03-09 02:00:00'} as dstlow, {ts '2014-11-02 02:00:00'} as dsthigh
UNION ALL SELECT {ts '2015-03-08 02:00:00'} as dstlow, {ts '2015-11-01 02:00:00'} as dsthigh
UNION ALL SELECT {ts '2016-03-13 02:00:00'} as dstlow, {ts '2016-11-06 02:00:00'} as dsthigh
UNION ALL SELECT {ts '2017-03-12 02:00:00'} as dstlow, {ts '2017-11-05 02:00:00'} as dsthigh
UNION ALL SELECT {ts '2018-03-11 02:00:00'} as dstlow, {ts '2018-11-04 02:00:00'} as dsthigh
) dst
on createdon >= dstlow and createdon < dsthigh
We can convert ServerZone DateTime to UTC and UTC to ServerZone DateTime
Simply run the following scripts to understand the conversion then modify as what you need
--Get Server's TimeZone
DECLARE #ServerTimeZone VARCHAR(50)
EXEC MASTER.dbo.xp_regread 'HKEY_LOCAL_MACHINE',
'SYSTEM\CurrentControlSet\Control\TimeZoneInformation',
'TimeZoneKeyName',#ServerTimeZone OUT
-- ServerZone to UTC DATETIME
DECLARE #CurrentServerZoneDateTime DATETIME = GETDATE()
DECLARE #UTCDateTime DATETIME = #CurrentServerZoneDateTime AT TIME ZONE #ServerTimeZone AT TIME ZONE 'UTC'
--(OR)
--DECLARE #UTCDateTime DATETIME = GETUTCDATE()
SELECT #CurrentServerZoneDateTime AS CURRENTZONEDATE,#UTCDateTime AS UTCDATE
-- UTC to ServerZone DATETIME
SET #CurrentServerZoneDateTime = #UTCDateTime AT TIME ZONE 'UTC' AT TIME ZONE #ServerTimeZone
SELECT #UTCDateTime AS UTCDATE,#CurrentServerZoneDateTime AS CURRENTZONEDATE
Note: This(AT TIME ZONE) working on only SQL Server 2016+ and this advantage is automatically considering Daylight while converting to particular Time zone
I'm a bit late to the game but I needed to do something like this on SQL 2012, I haven't fully tested it yet but here is what I came up with.
CREATE FUNCTION SMS.fnConvertUTC
(
#DateCST datetime
)
RETURNS DATETIME
AS
BEGIN
RETURN
CASE
WHEN #DateCST
BETWEEN
CASE WHEN #DateCST > '2007-01-01'
THEN CONVERT(DATETIME, CONVERT(VARCHAR,YEAR(#DateCST)) + '-MAR-14 02:00') - DATEPART(DW,CONVERT(VARCHAR,YEAR(#DateCST)) + '-MAR-14 02:00' ) + 1
ELSE CONVERT(DATETIME, CONVERT(VARCHAR,YEAR(#DateCST)) + '-APR-07 02:00') - DATEPART(DW,CONVERT(VARCHAR,YEAR(#DateCST)) + '-APR-07 02:00' ) + 1 END
AND
CASE WHEN #DateCST > '2007-01-01'
THEN CONVERT(DATETIME, CONVERT(VARCHAR,YEAR(#DateCST)) + '-NOV-07 02:00') - DATEPART(DW,CONVERT(VARCHAR,YEAR(#DateCST)) + '-NOV-07 02:00' ) + 1
ELSE CONVERT(DATETIME, CONVERT(VARCHAR,YEAR(#DateCST)) + '-OCT-31 02:00') - DATEPART(DW,CONVERT(VARCHAR,YEAR(#DateCST)) + '-OCT-31 02:00' ) + 1 END
THEN DATEADD(HOUR,4,#DateCST)
ELSE DATEADD(HOUR,5,#DateCST)
END
END
Above someone posted a static list DST dates so I wrote the below query to compare this code's output to that list... so far it looks correct.
;WITH DT AS
(
SELECT MyDate = GETDATE()
UNION ALL
SELECT MyDate = DATEADD(YEAR,-1,MyDate) FROM DT
WHERE DATEADD(YEAR,-1,MyDate) > DATEADD(YEAR, -30, GETDATE())
)
SELECT
SpringForward = CASE
WHEN MyDate > '2007-01-01'
THEN CONVERT(DATETIME, CONVERT(VARCHAR,YEAR(MyDate)) + '-MAR-14 02:00') - DATEPART(DW,CONVERT(VARCHAR,YEAR(MyDate)) + '-MAR-14 02:00' ) + 1
ELSE CONVERT(DATETIME, CONVERT(VARCHAR,YEAR(MyDate)) + '-APR-07 02:00') - DATEPART(DW,CONVERT(VARCHAR,YEAR(MyDate)) + '-APR-07 02:00' ) + 1 END
, FallBackward = CASE
WHEN MyDate > '2007-01-01'
THEN CONVERT(DATETIME, CONVERT(VARCHAR,YEAR(MyDate)) + '-NOV-07 02:00') - DATEPART(DW,CONVERT(VARCHAR,YEAR(MyDate)) + '-NOV-07 02:00' ) + 1
ELSE CONVERT(DATETIME, CONVERT(VARCHAR,YEAR(MyDate)) + '-OCT-31 02:00') - DATEPART(DW,CONVERT(VARCHAR,YEAR(MyDate)) + '-OCT-31 02:00' ) + 1 END
FROM DT
ORDER BY 1 DESC
SpringForward FallBackward
---------------- ----------------
2020-03-08 02:00 2020-11-01 02:00
2019-03-10 02:00 2019-11-03 02:00
2018-03-11 02:00 2018-11-04 02:00
2017-03-12 02:00 2017-11-05 02:00
2016-03-13 02:00 2016-11-06 02:00
2015-03-08 02:00 2015-11-01 02:00
2014-03-09 02:00 2014-11-02 02:00
2013-03-10 02:00 2013-11-03 02:00
2012-03-11 02:00 2012-11-04 02:00
2011-03-13 02:00 2011-11-06 02:00
2010-03-14 02:00 2010-11-07 02:00
2009-03-08 02:00 2009-11-01 02:00
2008-03-09 02:00 2008-11-02 02:00
2007-03-11 02:00 2007-11-04 02:00
2006-04-02 02:00 2006-10-29 02:00
2005-04-03 02:00 2005-10-30 02:00
2004-04-04 02:00 2004-10-31 02:00
2003-04-06 02:00 2003-10-26 02:00
2002-04-07 02:00 2002-10-27 02:00
2001-04-01 02:00 2001-10-28 02:00
2000-04-02 02:00 2000-10-29 02:00
1999-04-04 02:00 1999-10-31 02:00
1998-04-05 02:00 1998-10-25 02:00
1997-04-06 02:00 1997-10-26 02:00
1996-04-07 02:00 1996-10-27 02:00
1995-04-02 02:00 1995-10-29 02:00
1994-04-03 02:00 1994-10-30 02:00
1993-04-04 02:00 1993-10-31 02:00
1992-04-05 02:00 1992-10-25 02:00
1991-04-07 02:00 1991-10-27 02:00
(30 row(s) affected)
I have a date column where the date is displayed in the format 2009-11-18 10:55:28.370.
I just want to get the date (not time) out of that value. How do I do that?
If you're using SQL Server 2008, there is now a DATE datatype. Makes it a lot more natural!
SELECT CONVERT(Date, GETDATE())
it is called "flooring a datetime", do it like this to remove just the time (this is the fastest method, faster than using CONVERT() or CAST() sting formatting):
DECLARE #datetime datetime;
SET #datetime = '2008-09-17 12:56:53.430';
SELECT DATEADD(day,DATEDIFF(day,0,#datetime),0)
OUTPUT:
-----------------------
2008-09-17 00:00:00.000
(1 row(s) affected)
here is how to do it for other parts of a datetime:
--Floor a datetime
DECLARE #datetime datetime;
SET #datetime = '2008-09-17 12:56:53.430';
SELECT '0 None', #datetime -- none 2008-09-17 12:56:53.430
UNION SELECT '1 Second',DATEADD(second,DATEDIFF(second,'2000-01-01',#datetime),'2000-01-01') -- Second: 2008-09-17 12:56:53.000
UNION SELECT '2 Minute',DATEADD(minute,DATEDIFF(minute,0,#datetime),0) -- Minute: 2008-09-17 12:56:00.000
UNION SELECT '3 Hour', DATEADD(hour,DATEDIFF(hour,0,#datetime),0) -- Hour: 2008-09-17 12:00:00.000
UNION SELECT '4 Day', DATEADD(day,DATEDIFF(day,0,#datetime),0) -- Day: 2008-09-17 00:00:00.000
UNION SELECT '5 Month', DATEADD(month,DATEDIFF(month,0,#datetime),0) -- Month: 2008-09-01 00:00:00.000
UNION SELECT '6 Year', DATEADD(year,DATEDIFF(year,0,#datetime),0) -- Year: 2008-01-01 00:00:00.000
ORDER BY 1
PRINT' '
PRINT 'Note that when you are flooring by the second, you will often get an arithmetic overflow if you use 0. So pick a known value that is guaranteed to be lower than the datetime you are attempting to floor'
PRINT 'this always uses a date less than the given date, so there will be no arithmetic overflow'
SELECT '1 Second',DATEADD(second,DATEDIFF(second,DATEADD(day,DATEDIFF(day,0,#datetime),0)-1,#datetime),DATEADD(day,DATEDIFF(day,0,#datetime),0)-1) -- Second: 2008-09-17 12:56:53.000
OUTPUT:
-------- -----------------------
0 None 2008-09-17 12:56:53.430
1 Second 2008-09-17 12:56:53.000
2 Minute 2008-09-17 12:56:00.000
3 Hour 2008-09-17 12:00:00.000
4 Day 2008-09-17 00:00:00.000
5 Month 2008-09-01 00:00:00.000
6 Year 2008-01-01 00:00:00.000
(7 row(s) affected)
Note that when you are flooring by the second, you will often get an arithmetic overflow if you use 0. So pick a known value that is guaranteed to be lower than the datetime you are attempting to floor
this always uses a date less than the given date, so there will be no arithmetic overflow
-------- -----------------------
1 Second 2008-09-17 12:56:53.000
(1 row(s) affected)
If i got your question right,
select convert(varchar, creation_date , 103) as creation_date from tablename
Look at CAST and CONVERT
Here:
SELECT creation_date
FROM risks
WHERE creation_date = GETDATE()
This will return all creation_date values stored in the risks table that are exactly the same as what is returned by the GETDATE() function. I am assuming that the data type of creation_date is Date.
You just need to include creation_date in your select clause like this:
select id, creation_date from risks where creation_date = getdate()
You can always use the month/day/year functions to return it:
declare #date datetime
set #date = '1/1/10 12:00 PM'
select cast(month(#date) as varchar) + '/' + cast(day(#date) as varchar) + '/' + cast(year(#date) as varchar) as theDate