Reputation: 279
I would like into a stored procedure, truncate timestamp input values at the top hour or at the lower hour.
For example, if my input values are 2020-02-12 06:56:00
and 2020-02-12 07:14:00
, I would like to transforme it in 2020-02-12 06:00:00
and 2020-02-12 08:00:00
Is a cast function can work?
Upvotes: 0
Views: 706
Reputation: 24783
Using a bit of arithmetic calculation, convert to hours with decimal and use floor()
and ceiling()
to perform the round up / down
first it find the time different with 00:00:00
in terms of second. convert(date, date_col)
convert the datetime to date, so effectively it is 00:00:00
datediff(second, convert(date, date_col), date_col)
then you divide by 60 x 60 = 3600
seconds. Gives you fraction of hours
then you use floor()
or ceiling()
to perform the rounding
and lastly you add that back to the date (convert(date, date_col)
)
Final query
select *,
RoundDown = convert(datetime, convert(date, date_col))
+ dateadd(hour, floor(datediff(second, convert(date, date_col), date_col) / (3600.0)), 0),
RoundUp = convert(datetime, convert(date, date_col))
+ dateadd(hour, ceiling(datediff(second, convert(date, date_col), date_col) / (3600.0)), 0)
from (
values
('2020-02-12 06:56:00'),
('2020-02-12 07:14:00')
) d (date_col)
/*
2020-02-12 06:56:00 2020-02-12 06:00:00 2020-02-12 07:00:00
2020-02-12 07:14:00 2020-02-12 07:00:00 2020-02-12 08:00:00
*/
EDIT : a much simpler query below
find the different in minute
divide by 60.0
minutes to get different in terms of hour (with decimal places) and then apply floor
or ceiling
. Finally add that result back
select getdate() as Now,
dateadd(hour, floor(datediff(minute, 0, getdate()) / 60.0), 0) as RoundDown,
dateadd(hour, ceiling(datediff(minute, 0, getdate()) / 60.0), 0) as RoundUp
Upvotes: 1
Reputation: 795
This is a simpler solution:
declare @start datetime = '2020-02-12 06:56:00'
declare @end datetime = '2020-02-12 07:14:00'
select @start as OriginalStart,
@end as OriginalEnd,
dateadd(hour, datediff(hour, 0, @start), 0) as TruncatedStart,
dateadd(hour, datediff(hour, 0, dateadd(hour, 1, @end)), 0) as TruncatedEnd
In both cases the function substracts the hour part from the original timestamp. For the TruncatedEnd, one hour is added, so that the result is the subsequent hour.
Upvotes: 1
Reputation: 6465
You can construct the new datetimes from the parts that you want of your original datetimes.
declare @start datetime = '2020-02-12 06:56:00'
declare @end datetime = '2020-02-12 07:14:00'
select @start as OriginalStart,
@end as OriginalEnd,
datetimefromparts(year(@start), month(@start), day(@start), datepart(hour, @start), 0, 0, 0) as TruncatedStart,
dateadd(hour, 1, datetimefromparts(year(@end), month(@end), day(@end), datepart(hour, @end), 0, 0, 0)) as TruncatedEnd
The first truncation of the interval is the lower hour, and the second one adds an additional hour so it returns the higher hour.
PS: If what you want is to round to the nearest hour, then you can add 30 minutes and truncate :
declare @date datetime = '2020-02-12 06:56:00'
set @date = dateadd(minute, 30, @date)
select datetimefromparts(year(@date), month(@date), day(@date), datepart(hour, @date), 0, 0, 0) as NearestHour
or in a single step (using Lepetit's shortcut for truncation) :
declare @date datetime = '2020-02-12 06:56:00'
select dateadd(hour, datediff(hour, 0, dateadd(minute, 30, @date)), 0) AS NearestHour
Upvotes: 2