Rounding time untill in SQL - sql

I have a table with timestamp that I want to round off at 15 min. interval. I can round off using the below Query but it rounds off both 11:58 and 12:02 to 12:00 which is not what I want. I would like to round off timestamp at 15 min. interval which gives me time_untill ie for anything between 11:45 to 11:59 should be rounded off to 12 and anything between 12:00 to 12:14 should be rounded off to 12:15. Please let me know how can I achieve that? Thanks
SELECT transaction_id,
CONVERT(smalldatetime, ROUND(CONVERT(float, CONVERT(datetime, entry_date_time)) * 96.0, 0, 1) /96.0) as transaction_datetime
FROM <table>

You can use datetimefromparts():
select dateadd(minute,
15,
datetimefromparts(year(entry_date_time), month(entry_date_time), day(entry_date_time),
datepart(hour, entry_date_time),
15 * (datepart(minute, entry_date_time) / 15), 0, 0
)
) as roundup15

You could use the DATEADD/DATEDIFF method to truncate date/time values that's been available for a long time.
SELECT transaction_id,
entry_date_time,
DATEADD( MI, DATEDIFF( MI, '2010', entry_date_time)/15*15, '2010') as transaction_datetime
--FROM Sample Data
FROM (SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) transaction_id,
DATEADD( SS, CHECKSUM(NEWID())%10000, CAST( GETDATE() AS smalldatetime)) AS entry_date_time
FROM sys.columns)x;

Something like this...
DECLARE #time TIME(0) = GETDATE();
SELECT
DATEADD(MINUTE,
(((DATEDIFF(MINUTE, '00:00:00', #time) % 60) / 15) * 15),
DATEADD(HOUR, DATEDIFF(HOUR, '00:00:00', #time), '00:00:00')
);

Related

Truncate timestamp

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?
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
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.
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

Displaying Full DateTime when sorting by hour

I am using microsoft sql server. I am trying to sort my results by the full time.
My raw data looks like this:
TimeStamp TotalOffered
2012-04-16 08:00:00 18
2012-04-16 08:30:00 34
2012-04-16 09:00:00 30
2012-04-16 09:30:00 68
I am sorting by hour blocks for example sum of data during 08:00:00 is 52, sum of data for 09:00:00 is 98, I have it broken down by day.
The Code i have is:
select datepart(hour,[TimeStamp]), SUM([TotalOffered])
from [my table]
group by
datepart(hour,[sus_CallPerformance_TimeStamp]),
dateadd(d, 0, datediff(d, 0, [sus_CallPerformance_TimeStamp]))
I am trying to get the data to show the full TimeStamp instead of just the hour.
Currently the results show as:
8 52
9 98
I would like the results to show as:
2012-04-16 08:00:00 52
2012-04-16 09:00:00 98
Thank You
SELECT DATEADD(HOUR, DATEPART(HOUR, TimeStamp), DATEDIFF(DAY, 0, TimeStamp)) [TimeStamp],
SUM(TotalOffered) [TotalOffered]
FROM [My Table]
GROUP BY DATEADD(HOUR, DATEPART(HOUR, TimeStamp), DATEDIFF(DAY, 0, TimeStamp))
ORDER BY [TimeStamp]
try this:
declare #t table (ts datetime, od int)
insert into #t (ts, od) values ('2012-04-16 08:00:00', 18)
insert into #t (ts, od) values ('2012-04-16 08:30:00', 34)
insert into #t (ts, od) values ('2012-04-16 09:00:00', 30)
insert into #t (ts, od) values ('2012-04-16 09:30:00', 68)
select * from #t
select
dateadd(hour, datepart(hour, ts), cast(floor(cast(ts as real)) as datetime)) as solution,
sum(od)
from #t
group by dateadd(hour, datepart(hour, ts), cast(floor(cast(ts as real)) as datetime))
order by dateadd(hour, datepart(hour, ts), cast(floor(cast(ts as real)) as datetime))
DateTime fields can be cast to floating point values, where the whole number represents the date and the fraction represents the time. If you multipy the date by 24, then the whole number will represent the hour, as follows:
SELECT CAST(FLOOR(CAST(TimeStamp AS FLOAT) * 24)/24.0 AS DateTime) AS Hr, SUM(TotalOffered) AS Total
FROM [my table]
GROUP BY FLOOR(CAST(TimeStamp AS FLOAT) * 24)
ORDER BY FLOOR(CAST(TimeStamp AS FLOAT) * 24)

SQL Server - Round TIME values to the next minute

I've found many posts about rounding "down" time values (e.g. https://stackoverflow.com/a/6667041/468823), but I have another problem: I wanna round to the higher minute and not to the lower, how can I do?
My code:
SELECT
PA.ORE AS TOT_HOURS,
CAST(CAST(PA.ORA_INIZIO AS DATETIME) AS TIME) AS BEGIN_TIME,
CAST(dateadd(minute, datediff(minute, 0, (CAST(PA.ORA_INIZIO AS DATETIME))), 0) AS TIME) AS BEGIN_TIME_ROUNDED
FROM PRG_ATTIVITA PA INNER JOIN PRG_TIPI_ATTIVITA PTA ON PA.ID_TIPO_ATTIVITA = PTA.ID_TIPO_ATTIVITA
INNER JOIN PER_ANAGRAFICA PAN ON PA.ID_DIPENDENTE = PAN.ID_DIPENDENTE
WHERE PA.ID_PROGETTO = 1431 and pta.DESCR_TIPO_ATTIVITA like 'F-%remoto%' and ID_ATTIVITA = 41772
ORDER BY PA.DATA_ATTIVITA
My result is the following:
TOT_HOURS BEGIN_TIME BEGIN_TIME_ROUNDED
1.50 15:59:59.9970000 15:59:00.0000000
I want BEGIN_TIME_ROUNDED = 16:00:00.0000000
NOTES:
1. I must convert my data { CAST(PA.ORA_INIZIO AS DATETIME) } because in the database I have time data as float values
2. BEGIN_TIME is the real value of my time value after conversion
SELECT DATEADD(MINUTE, CEILING(DATEDIFF(SECOND, 0, CAST(CAST(PA.ORA_INIZIO AS DATETIME) AS TIME)) / 60.0), DATEDIFF(DAY, 0, PA.ORA_INIZIO)) AS BEGIN_TIME_ROUNDED
EDIT
As pointed out in a comment this fails for times between 0 and 1 second. This can be combatted by simply changing the precision in the ceiling from seconds to milliseconds:
SELECT PA.ORA_INIZIO,
DATEADD(MINUTE,
CEILING(DATEDIFF(MILLISECOND, 0, CAST(PA.ORA_INIZIO AS TIME)) / 60000.0),
DATEDIFF(DAY, 0, PA.ORA_INIZIO)) AS BEGIN_TIME_ROUNDED
FROM (VALUES
(CONVERT(DATETIME, '20211126 15:59:00.997')),
(CONVERT(DATETIME, '20211126 15:59:00.004'))
) AS PA (ORA_INIZIO);
Which gives:
ORA_INIZIO
BEGIN_TIME_ROUNDED
2021-11-26 15:59:59.997
2021-11-26 16:00:00.000
2021-11-26 15:59:00.003
2021-11-26 16:00:00.000
Just CAST to smalldatetime for rounding to nearest minute
SELECT
CAST(CAST('15:59:59.9970000' AS time) AS smalldatetime),
CAST(CAST('15:59:30.0030000' AS time) AS smalldatetime),
CAST(CAST('15:59:30.0000000' AS time) AS smalldatetime),
CAST(CAST('15:59:29.9970000' AS time) AS smalldatetime),
CAST(CAST('15:59:00.0030000' AS time) AS smalldatetime)
The DATEADD/DATEDIFF is for truncating some time unit
Edit, misread questions
Just modify your current CAST
CAST(
DATEADD(minute,
DATEDIFF(minute,
0,
CAST(PA.ORA_INIZIO AS DATETIME)
) + 1,
0
)
AS TIME)
Don't know SQL Server well enough to answer off hand, but if no one comes by with a more more de facto way of doing this, then you could just add 1 minute to the value before rounding it down. Or add 0.999 minutes if you need to handle integer input values correctly as well.
If you wanted to round DATETIME d up to the nearest minute, you could do this:
CONVERT(DATETIME, CONVERT(SMALLDATETIME,
DATEADD(minute, CASE WHEN d = CONVERT(SMALLDATETIME, d) THEN 0 ELSE 1 END,
d)))
DECLARE # datetime = '2021-11-26 00:00:00.997'
SELECT dateadd(minute, ceiling(cast(# as float) * 1440),0) ceilingminute

SQL Server: hour and minute average

In SQL Server, I have a start time column on a table such as:
2011-09-18 08:06:36.000
2011-09-19 05:42:16.000
2011-09-20 08:02:26.000
2011-09-21 08:37:24.000
2011-09-22 08:22:20.000
2011-09-23 11:58:27.000
2011-09-24 09:00:48.000
2011-09-25 06:51:34.000
2011-09-26 06:09:05.000
2011-09-27 08:25:26.000
...
My question is, how can I get the average hour and minute? I want to know that what is the average start time for this job. (for example 07:22)
I tried something like this but didn't work:
select CAST(AVG(CAST(DATEPART(HH, START_TIME)AS float)) AS datetime) FROM
Thanks.
declare #T table(StartTime datetime)
insert into #T values
('2011-09-18 08:06:36.000'),
('2011-09-19 05:42:16.000'),
('2011-09-20 08:02:26.000'),
('2011-09-21 08:37:24.000'),
('2011-09-22 08:22:20.000'),
('2011-09-23 11:58:27.000'),
('2011-09-24 09:00:48.000'),
('2011-09-25 06:51:34.000'),
('2011-09-26 06:09:05.000'),
('2011-09-27 08:25:26.000')
;with C(Sec) as
(
select dateadd(second, avg(datediff(second, dateadd(day, datediff(day, 0, StartTime), 0), StartTime)), 0)
from #T
)
select convert(char(5), dateadd(minute, case when datepart(second, C.Sec) >= 30 then 1 else 0 end, C.Sec), 108)
from C
-----
08:08
Try this :
select CAST((SUM(DATEPART(HH, START_TIME) * 60 + DATEPART(MI, START_TIME))/COUNT(*))/60 AS VARCHAR(10)) + ':' + CAST((SUM(DATEPART(HH, START_TIME) * 60 + DATEPART(MI, START_TIME))/COUNT(*))%60 AS VARCHAR(10))
FROM.....

How to display roundof time

Using SQL Server 2005
Table1
ID Intime Outtime
001 00.21.00 00.48.00
002 08.23.00 13.45.00
003 00.34.00 00.18.00
I need to display the time time like 30 minutes or 1 Hours, it should display a roundoff time
Expected Output
ID Intime Outtime
001 00.30.00 01.00.00
002 08.30.00 14.00.00
003 01.00.00 00.30.00
How to make a query for the roundoff time.
You can round the current date to 30 minutes like:
select dateadd(mi, datediff(mi,0,getdate())/30*30, 0)
Explanation: this takes the number of minutes since the 0-date:
datediff(mi,0,getdate())
Then it rounds that to a multiple of 30 by dividing and multiplying by 30:
datediff(mi,0,getdate())/30*30
The result is added back to the 0-date to find the last 30 minute block
dateadd(mi, datediff(mi,0,getdate())/30*30, 0)
This can be adjusted easily for 60 minutes. :)
By checking the range
select ID,
DateAdd(mi, DateDiff(mi, 0, Intime +
case when InMi >= 15 then 30 - InMi else - InMi end), 0) as Intime,
DateAdd(mi, DateDiff(mi, 0, Outtime +
case when OutMi >= 15 then 30 - OutMi else - OutMi end), 0) as Outtime
FROM
(
select ID, Intime, Outtime,
datepart(mi, InTime) % 30 InMi,
datepart(mi, Outtime) % 30 OutMi
from tbl
) X
or by using the classical trick equivalent to Int(x+0.5)..
select ID,
dateadd(mi, ((datediff(mi, 0, Intime)+15)/30)*30, 0) Intime,
dateadd(mi, ((datediff(mi, 0, Outtime)+15)/30)*30, 0) Outtime
from tbl
IF you want to ROUNDUP instead
(you have a value going from 00.34.00 to 01.00.00) Then you need this
select ID,
dateadd(mi, ((datediff(mi, 0, Intime)+29)/30)*30, 0) Intime,
dateadd(mi, ((datediff(mi, 0, Outtime)+29)/30)*30, 0) Outtime
from tbl
Take a look at the DATEDIFF, DATEADD and DATEPART. You should be able to do what you want with that.
http://msdn.microsoft.com/en-us/library/ms189794.aspx
http://msdn.microsoft.com/en-us/library/ms186819.aspx
http://msdn.microsoft.com/en-us/library/ms174420.aspx
Here is kind of a step-by-step routine. I'm sure you can do something shorter and even more efficient. It would also simplify a lot if you used a datetime data type instead of a string.
declare #T table (id char(3), intime char(8), outtime char(8))
insert into #T values ('001', '00.21.00', '00.48.00')
insert into #T values ('002', '08.23.00', '13.45.00')
insert into #T values ('003', '00.34.00', '00.18.00')
;with
cteTime(id, intime, outtime)
as
( -- Convert to datetime
select
id,
cast(replace(intime, '.', ':') as datetime),
cast(replace(outtime, '.', ':') as datetime)
from #T
),
cteMinute(id, intime, outtime)
as
( -- Get the minute part
select
id,
datepart(mi, intime),
datepart(mi, outtime)
from cteTime
),
cteMinuteDiff(id, intime, outtime)
as
( -- Calcualte the desired diff
select
id,
case when intime > 30 then (60 - intime) else (30 - intime) end,
case when outtime > 30 then (60 - outtime) else (30 - outtime) end
from cteMinute
),
cteRoundTime(id, intime, outtime)
as
( -- Get the rounded time
select
cteTime.id,
dateadd(mi, cteMinuteDiff.intime, cteTime.intime),
dateadd(mi, cteMinuteDiff.outtime, cteTime.outtime)
from cteMinuteDiff
inner join cteTime
on cteMinuteDiff.id = cteTime.id
),
cteRoundedTimeParts(id, inHour, inMinute, outHour, outMinute)
as
( -- Split the time into parts
select
id,
cast(datepart(hh, intime) as varchar(2)) as inHour,
cast(datepart(mi, intime) as varchar(2)) as inMinute,
cast(datepart(hh, outtime) as varchar(2)) as outHour,
cast(datepart(mi, outtime) as varchar(2)) as outMinute
from cteRoundTime
),
cteRoundedTime(id, intime, outtime)
as
( -- Build the time string representation
select
id,
right('00'+inHour, 2)+'.'+right('00'+inMinute, 2)+'.00',
right('00'+outHour, 2)+'.'+right('00'+outMinute, 2)+'.00'
from cteRoundedTimeParts
)
select *
from cteRoundedTime