In SQL server 2008, I would like to get datetime column rounded to nearest hour and nearest minute preferably with existing functions in 2008.
For this column value 2007-09-22 15:07:38.850, the output will look like:
2007-09-22 15:08 -- nearest minute
2007-09-22 15 -- nearest hour
declare #dt datetime
set #dt = '09-22-2007 15:07:38.850'
select dateadd(mi, datediff(mi, 0, #dt), 0)
select dateadd(hour, datediff(hour, 0, #dt), 0)
will return
2007-09-22 15:07:00.000
2007-09-22 15:00:00.000
The above just truncates the seconds and minutes, producing the results asked for in the question. As #OMG Ponies pointed out, if you want to round up/down, then you can add half a minute or half an hour respectively, then truncate:
select dateadd(mi, datediff(mi, 0, dateadd(s, 30, #dt)), 0)
select dateadd(hour, datediff(hour, 0, dateadd(mi, 30, #dt)), 0)
and you'll get:
2007-09-22 15:08:00.000
2007-09-22 15:00:00.000
Before the date data type was added in SQL Server 2008, I would use the above method to truncate the time portion from a datetime to get only the date. The idea is to determine the number of days between the datetime in question and a fixed point in time (0, which implicitly casts to 1900-01-01 00:00:00.000):
declare #days int
set #days = datediff(day, 0, #dt)
and then add that number of days to the fixed point in time, which gives you the original date with the time set to 00:00:00.000:
select dateadd(day, #days, 0)
or more succinctly:
select dateadd(day, datediff(day, 0, #dt), 0)
Using a different datepart (e.g. hour, mi) will work accordingly.
"Rounded" down as in your example. This will return a varchar value of the date.
DECLARE #date As DateTime2
SET #date = '2007-09-22 15:07:38.850'
SELECT CONVERT(VARCHAR(16), #date, 120) --2007-09-22 15:07
SELECT CONVERT(VARCHAR(13), #date, 120) --2007-09-22 15
I realize this question is ancient and there is an accepted and an alternate answer. I also realize that my answer will only answer half of the question, but for anyone wanting to round to the nearest minute and still have a datetime compatible value using only a single function:
CAST(YourValueHere as smalldatetime);
For hours or seconds, use Jeff Ogata's answer (the accepted answer) above.
Select convert(char(8), DATEADD(MINUTE, DATEDIFF(MINUTE, 0, getdate), 0), 108) as Time
will round down seconds to 00
Related
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've been writing queries to truncate the time from a given datetime for years now, based on answers like this one and this one (and many other places), that groups a couple functions like
SELECT DATEADD(day, 0, DATEDIFF(day, 0, getdate()))
and it always gives the right answer.
I figured I could translate the same logic to finding the first of the current month by using month instead of day, but it's giving me a weird date for the result: 1903-10-17, instead of 2015-05-01.
My parameters have always been in the wrong order.
It turns out the format for DATEADD I've been using all these years is wrong, and it's only been working because it's using the day datepart. Casting an int to a date increments the day:
SELECT CAST(0 AS datetime) = '1900-01-01 00:00:00.000'
SELECT CAST(1 AS datetime) = '1900-01-02 00:00:00.000'
SELECT CAST(2 AS datetime) = '1900-01-03 00:00:00.000'
I should be using DATEADD(d, DATEDIFF(d, 0, getdate()), 0) - the parameters are (datepart, number, date), as laid out here at MSDN.
Writing it as SELECT DATEADD(month, DATEDIFF(month, 0, getdate()), 0) gives the expected result of 2015-05-01.
I'd like to get 4:30 PM of the current day. Hard-coding this way doesn't work:
SELECT '07242012 16:30:00.000'
This is proving to be more difficult than I thought it would be. How do I approach this?
SQL Server 2000 / 2005:
SELECT DATEADD(MINUTE, 30, DATEADD(HOUR, 16, DATEDIFF(DAY, 0, CURRENT_TIMESTAMP)));
-- or
SELECT DATEADD(MINUTE, (16*60) + 30, DATEDIFF(DAY, 0, CURRENT_TIMESTAMP))
-- or
SELECT CONVERT(DATETIME, CONVERT(CHAR(9), CURRENT_TIMESTAMP, 112) + '16:30');
SQL Server 2008+:
SELECT CONVERT(DATETIME, CONVERT(DATE, CURRENT_TIMESTAMP)) + '16:30';
SQL Server 2012:
SELECT SMALLDATETIMEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), DAY(GETDATE()), 16, 30);
Probably the easiest thing to do is to cast the current date/time to a date (stripping the time off), cast it back to a datetime to allow use of datetime's overloaded + (plus) and, finally cast your desired textual time to a datetime. As follows:
select cast(cast(sysutcdatetime() as date) as datetime) + cast('16:30' as datetime)
returns (when run on 11th Jan 2018):
2018-01-11 16:30:00.000
You can construct this as you like with day, hour, minute etc.
SELECT CURDATE() - interval 1 DAY + interval 2
select(dateadd(day, datediff(day, 0, getdate()), 0) + '20:00') as specified_date
specified_date - Output Column name
20:00 - Specified time(24 hr Format -Default)
getdate() - To get Today's date.
SQL Server, trying to get day of week via a deterministic UDF.
Im sure this must be possible, but cant figure it out.
UPDATE: SAMPLE CODE..
CREATE VIEW V_Stuff WITH SCHEMABINDING AS
SELECT
MD.ID,
MD.[DateTime]
...
dbo.FN_DayNumeric_DateTime(MD.DateTime) AS [Day],
dbo.FN_TimeNumeric_DateTime(MD.DateTime) AS [Time],
...
FROM {SOMEWHERE}
GO
CREATE UNIQUE CLUSTERED INDEX V_Stuff_Index ON V_Stuff (ID, [DateTime])
GO
Ok, i figured it..
CREATE FUNCTION [dbo].[FN_DayNumeric_DateTime]
(#DT DateTime)
RETURNS INT WITH SCHEMABINDING
AS
BEGIN
DECLARE #Result int
DECLARE #FIRST_DATE DATETIME
SELECT #FIRST_DATE = convert(DATETIME,-53690+((7+5)%7),112)
SET #Result = datediff(dd,dateadd(dd,(datediff(dd,#FIRST_DATE,#DT)/7)*7,#FIRST_DATE), #DT)
RETURN (#Result)
END
GO
Slightly similar approach to aforementioned solution, but just a one-liner that could be used inside a function or inline for computed column.
Assumptions:
You don't have dates before
1899-12-31 (which is a Sunday)
You want to imitate ##datefirst = 7
#dt is smalldatetime, datetime,
date, or datetime2 data type
If you'd rather it be different, change the date '18991231' to a date with the weekday that you'd like to equal 1. The convert() function is key to making the whole thing work - cast does NOT do the trick:
((datediff(day, convert(datetime,
'18991231', 112), #dt) % 7)
+ 1)
I know this post is way-super-old, but I was trying to do a similar thing and came up with a different solution and figured I'd post for posterity. Plus I did some searching around and did not find much content on this question.
In my case, I was trying to use a computed column PERSISTED, which requires the calculation to be deterministic. The calculation I used is:
datediff(dd,'2010-01-03',[DateColumn]) % 7 + 1
The idea is to figure out a known Sunday that you know will occur before any possible date in your table (in this case, Jan 3 2010), then calculate the modulo 7 + 1 of the number of days since that Sunday.
The problem is that including a literal date in the function call is enough to mark it as non-deterministic. You can work around that by using the integer 0 to represent the epoch, which for SQL Server is Jan 1st, 1900, a Sunday.
datediff(dd,0,[DateColumn]) % 7 + 1
The +1 just makes the result work the same as datepart(dw,[datecolumn]) when datefirst is set to 7 (default for US), which sets Sunday to 1, Monday to 2, etc
I can also use this in conjunction with case [thatComputedColumn] when 1 then 'Sunday' when 2 then 'Monday' ... etc. Wordier, but deterministic, which was a requirement in my environs.
Taken from Deterministic scalar function to get week of year for a date
;
with
Dates(DateValue) as
(
select cast('2000-01-01' as date)
union all
select dateadd(day, 1, DateValue) from Dates where DateValue < '2050-01-01'
)
select
year(DateValue) * 10000 + month(DateValue) * 100 + day(DateValue) as DateKey, DateValue,
datediff(day, dateadd(week, datediff(week, 0, DateValue), 0), DateValue) + 2 as DayOfWeek,
datediff(week, dateadd(month, datediff(month, 0, DateValue), 0), DateValue) + 1 as WeekOfMonth,
datediff(week, dateadd(year, datediff(year, 0, DateValue), 0), DateValue) + 1 as WeekOfYear
from Dates option (maxrecursion 0)
There is an already built-in function in sql to do it:
SELECT DATEPART(weekday, '2009-11-11')
EDIT:
If you really need deterministic UDF:
CREATE FUNCTION DayOfWeek(#myDate DATETIME )
RETURNS int
AS
BEGIN
RETURN DATEPART(weekday, #myDate)
END
GO
SELECT dbo.DayOfWeek('2009-11-11')
EDIT again: this is actually wrong, as DATEPART(weekday) is not deterministic.
UPDATE:
DATEPART(weekday) is non-deterministic because it relies on DATEFIRST (source).
You can change it with SET DATEFIRST but you can't call it inside a stored function.
I think the next step is to make your own implementation, using your preferred DATEFIRST inside it (and not considering it at all, using for example Monday as first day).
The proposed solution has one problem - it returns 0 for Saturdays. Assuming that we're looking for something compatible with DATEPART(WEEKDAY) this is an issue.
Nothing a simple CASE statement won't fix, though.
Make a function, and have #dbdate varchar(8) as your input variable.
Have it return the following:
RETURN (DATEDIFF(dd, -1, convert(datetime, #dbdate, 112)) % 7)+1;
The value 112 is the sql style YYYYMMDD.
This is deterministic because the datediff does not receive a string input, if it were to receive a string it would no longer work because it internally converts it to a datetime object. Which is not deterministic.
Not sure what you are looking for, but if this is part of a website, try this php function from http://php.net/manual/en/function.date.php
function weekday($fyear, $fmonth, $fday) //0 is monday
{
return (((mktime ( 0, 0, 0, $fmonth, $fday, $fyear) - mktime ( 0, 0, 0, 7, 17, 2006))/(60*60*24))+700000) % 7;
}
The day of the week? Why don't you just use DATEPART?
DATEPART(weekday, YEAR_DATE)
Can't you just select it with something like:
SELECT DATENAME(dw, GETDATE());
In SQL Server, how do I "floor" a DATETIME to the second/minute/hour/day/year?
Let's say that I have a date of 2008-09-17 12:56:53.430, then the output of flooring should be:
Year: 2008-01-01 00:00:00.000
Month: 2008-09-01 00:00:00.000
Day: 2008-09-17 00:00:00.000
Hour: 2008-09-17 12:00:00.000
Minute: 2008-09-17 12:56:00.000
Second: 2008-09-17 12:56:53.000
The key is to use DATEADD and DATEDIFF along with the appropriate SQL timespan enumeration.
declare #datetime datetime;
set #datetime = getdate();
select #datetime;
select dateadd(year,datediff(year,0,#datetime),0);
select dateadd(month,datediff(month,0,#datetime),0);
select dateadd(day,datediff(day,0,#datetime),0);
select dateadd(hour,datediff(hour,0,#datetime),0);
select dateadd(minute,datediff(minute,0,#datetime),0);
select dateadd(second,datediff(second,'2000-01-01',#datetime),'2000-01-01');
select dateadd(week,datediff(week,0,#datetime),-1); --Beginning of week is Sunday
select dateadd(week,datediff(week,0,#datetime),0); --Beginning of week is Monday
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.
In SQL Server here's a little trick to do that:
SELECT CAST(FLOOR(CAST(CURRENT_TIMESTAMP AS float)) AS DATETIME)
You cast the DateTime into a float, which represents the Date as the integer portion and the Time as the fraction of a day that's passed. Chop off that decimal portion, then cast that back to a DateTime, and you've got midnight at the beginning of that day.
This is probably more efficient than all the DATEADD and DATEDIFF stuff. It's certainly way easier to type.
Expanding upon the Convert/Cast solution, in Microsoft SQL Server 2008 you can do the following:
cast(cast(getdate() as date) as datetime)
Just replace getdate() with any column which is a datetime.
There are no strings involved in this conversion.
This is ok for ad-hoc queries or updates, but for key joins or heavily used processing it may be better to handle the conversion within the processing or redefine the tables to have appropriate keys and data.
In 2005, you can use the messier floor: cast(floor(cast(getdate() as float)) as datetime)
I don't think that uses string conversion either, but I can't speak to comparing actual efficiency versus armchair estimates.
I've used #Portman's answer many times over the years as a reference when flooring dates and have moved its working into a function which you may find useful.
I make no claims to its performance and merely provide it as a tool for the user.
I ask that, if you do decide to upvote this answer, please also upvote #Portman's answer, as my code is a derivative of his.
IF OBJECT_ID('fn_FloorDate') IS NOT NULL DROP FUNCTION fn_FloorDate
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[fn_FloorDate] (
#Date DATETIME = NULL,
#DatePart VARCHAR(6) = 'day'
)
RETURNS DATETIME
AS
BEGIN
IF (#Date IS NULL)
SET #Date = GETDATE();
RETURN
CASE
WHEN LOWER(#DatePart) = 'year' THEN DATEADD(YEAR, DATEDIFF(YEAR, 0, #Date), 0)
WHEN LOWER(#DatePart) = 'month' THEN DATEADD(MONTH, DATEDIFF(MONTH, 0, #Date), 0)
WHEN LOWER(#DatePart) = 'day' THEN DATEADD(DAY, DATEDIFF(DAY, 0, #Date), 0)
WHEN LOWER(#DatePart) = 'hour' THEN DATEADD(HOUR, DATEDIFF(HOUR, 0, #Date), 0)
WHEN LOWER(#DatePart) = 'minute' THEN DATEADD(MINUTE, DATEDIFF(MINUTE, 0, #Date), 0)
WHEN LOWER(#DatePart) = 'second' THEN DATEADD(SECOND, DATEDIFF(SECOND, '2000-01-01', #Date), '2000-01-01')
ELSE DATEADD(DAY, DATEDIFF(DAY, 0, #Date), 0)
END;
END
Usage:
DECLARE #date DATETIME;
SET #date = '2008-09-17 12:56:53.430';
SELECT
#date AS [Now],--2008-09-17 12:56:53.430
dbo.fn_FloorDate(#date, 'year') AS [Year],--2008-01-01 00:00:00.000
dbo.fn_FloorDate(default, default) AS [NoParams],--2013-11-05 00:00:00.000
dbo.fn_FloorDate(#date, default) AS [ShouldBeDay],--2008-09-17 00:00:00.000
dbo.fn_FloorDate(#date, 'month') AS [Month],--2008-09-01 00:00:00.000
dbo.fn_FloorDate(#date, 'day') AS [Day],--2008-09-17 00:00:00.000
dbo.fn_FloorDate(#date, 'hour') AS [Hour],--2008-09-17 12:00:00.000
dbo.fn_FloorDate(#date, 'minute') AS [Minute],--2008-09-17 12:56:00.000
dbo.fn_FloorDate(#date, 'second') AS [Second];--2008-09-17 12:56:53.000
The CONVERT() function can do this as well, depending on what style you use.
Too bad it's not Oracle, or else you could use trunc() or to_char().
But I had similar issues with SQL Server and used the CONVERT() and DateDiff() methods, as referenced here
There are several ways to skin this cat =)
select convert(datetime,convert(varchar,CURRENT_TIMESTAMP,101))
DateAdd along with DateDiff can help to do many different tasks. For example, you can find last day of any month as well can find last day of previous or next month.
----Last Day of Previous Month
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0))
LastDay_PreviousMonth
----Last Day of Current Month
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+1,0))
LastDay_CurrentMonth
----Last Day of Next Month
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+2,0))
LastDay_NextMonth
Source
Since PostgreSQL is also a "SQL Server", I'll mention
date_trunc()
Which does exactly what you're asking gracefully.
For example:
select date_trunc('hour',current_timestamp);
date_trunc
------------------------
2009-02-18 07:00:00-08
(1 row)