I have a list of schedule that looks like this
Start Time 2016-6-20 7:30AM End Time 2016-6-20 8:00AM
I want to create a query to calculate the duration between the intervals, it would work for 30 minutes but I don’t know how to create one for when it ends on 2:45 or 2:15. If I do date diff I would give me 30 minutes duration but for 2:15 or 2:45 it will not give me that
I want something to look like
7:30, Start time7:30, End Time 8:00AM, durwtion 30 minutes
8:00, Start time 8:00, End time 8:15, duration 15 minutes
do you mean something like this? fixing it up for hr:min would be a task, but minutes is easy.
declare #starttime datetime = '2016-6-20 7:30AM'
declare #endtime datetime = '2016-6-20 8:00AM'
select rtrim(datediff(minute,#starttime, #endtime)) + ' min'
edit, try this query
;with duration_dates as
(
SELECT top (100)
dateadd(minute,(datediff(minute,0,Start_Time_UTC)/ 15)*15,0) Start_Time_UTC
,dateadd(minute,(datediff(minute,0,dateadd(minute,15,End_time_UTC))/15)*15,0) End_time_UTC
--,<your id column here>
FROM EmployeeSchedules
)
SELECT
TimeInterval
,Start_Time_UTC
,End_time_UTC
,datediff(minute, Start_Time_UTC,End_time_UTC) duration
FROM Times
LEFT JOIN duration_dates ON CAST(Start_Time_UTC AS Time) = TimeInterval
Related
Let's suppose that some event started on 1st January 2000 and is repeated every 36 hours and 45 minutes.
At this moment at my place it is 4th April 2018 18:30.
How could I calculate in SQL
date and time of last recent happening of my event
date and time of next future happening of my event ?
My first idea was adding my period in a loop to a start date until required date is reached but that would be very ineffective with longer time spans, I believe
Thank you for any help.
We could parameterize an sql statement with the results of this integer math...
int now = current time in minutes after 1 Jan, 2000
int period = 36 * 60 + 45
int eventsBeforeNow = now / period /* where '/' is a truncating, integer divide */
int lastEventTime = eventsBeforeNow * period
int nextEventTime = lastEventTime + period
Okay, I found the answer myself. Seems to work
declare #minutes int,#n int,#period int
SET #period=36*60+45
select #minutes=datediff(minute,'2000-01-01 00:00:00','2018-04-04 18:30:00')
set #n=#minutes/#period
select DATEADD(minute,#n*#period,'2000-01-01 00:00:00')
select DATEADD(minute,(#n+1)*#period,'2000-01-01 00:00:00')
Recent time of my example event is 2018-04-04 14:15:00.000
Next time of my example event is 2018-04-06 03:00:00.000
I'm calculating average start times from events that run late at night and may not start until the next morning.
2018-01-09 00:01:38.000
2018-01-09 23:43:22.000
currently all I can produce is an average of 11:52:30.0000000
I would like the result to be ~ 23:52
the times averaged will not remain static as this event runs daily and I will have new data daily. I will likely take the most recent 10 records and average them.
Would be nice to have SQL you're running, but probably you just need to format properly your output, it should be something like this:
FORMAT(cast(<your column> as time), N'hh\:mm(24h)')
The following will both compute the average across the datetime field and also return the result as a 24hr time notation only.
SELECT CAST(CAST(AVG(CAST(<YourDateTimeField_Here> AS FLOAT)) AS DATETIME) AS TIME) [AvgTime] FROM <YourTableContaining_DateTime>
The following will calculate the average time of day, regardless of what day that is.
--SAMPLE DATA
create table #tmp_sec_dif
(
sample_date_time datetime
)
insert into #tmp_sec_dif
values ('2018-01-09 00:01:38.000')
, ('2018-01-09 23:43:22.000')
--ANSWER
declare #avg_sec_dif int
set #avg_sec_dif =
(select avg(a.sec_dif) as avg_sec_dif
from (
--put the value in terms of seconds away from 00:00:00
--where 23:59:00 would be -60 and 00:01:00 would be 60
select iif(
datepart(hh, sample_date_time) < 12 --is it morning?
, datediff(s, '00:00:00', cast(sample_date_time as time)) --if morning
, datediff(s, '00:00:00', cast(sample_date_time as time)) - 86400 --if evening
) as sec_dif
from #tmp_sec_dif
) as a
)
select cast(dateadd(s, #avg_sec_dif, '00:00:00') as time) as avg_time_of_day
The output would be an answer of 23:52:30.0000000
This code allows you to define a date division point. e.g. 18 identifies 6pm. The time calculation would then be based on seconds after 6pm.
-- Defines the hour of the day when a new day starts
DECLARE #DayDivision INT = 18
IF OBJECT_ID(N'tempdb..#StartTimes') IS NOT NULL DROP TABLE #StartTimes
CREATE TABLE #StartTimes(
start DATETIME NOT NULL
)
INSERT INTO #StartTimes
VALUES
('2018-01-09 00:01:38.000')
,('2018-01-09 23:43:22.000')
SELECT
-- 3. Add the number of seconds to a day starting at the
-- day division hour, then extract the time portion
CAST(DATEADD(SECOND,
-- 2. Average number of seconds
AVG(
-- 1. Get the number of seconds from the day division point (#DayDivision)
DATEDIFF(SECOND,
CASE WHEN DATEPART(HOUR,start) < #DayDivision THEN
SMALLDATETIMEFROMPARTS(YEAR(DATEADD(DAY,-1,start)),MONTH(DATEADD(DAY,-1,start)),DAY(DATEADD(DAY,-1,start)),#DayDivision,0)
ELSE
SMALLDATETIMEFROMPARTS(YEAR(start),MONTH(start),DAY(start),#DayDivision,0)
END
,start)
)
,'01 jan 1900 ' + CAST(#DayDivision AS VARCHAR(2)) + ':00') AS TIME) AS AverageStartTime
FROM #StartTimes
I need to write a function that rounds time in one column, called StartTime, to display just the hour and insert it to another column called StartHour. In another column, called EndTime, I also need to use DATEPART to round up to the next incremented hour (ex: 23:33:00.0000000 would be 23 (the hour) + 1 (to round it up to the end hour) = 24 and I would need to save that to the EndHour column).
I want to insert these new values into new columns called StartHour and StartMinute, EndHour, and EndMinute (the StartTime and EndTime columns are the original values I'm working with in time(7) format and for historical purposes, I'm keeping them in their original columns).
Here's what I have so far in T-SQL:
SELECT (DATEPART(HOUR, [StartTime])) AS StartHour,(DATEPART(MINUTE, [StartTime])) AS StartMinute,
(DATEPART(HOUR, [EndTime])) AS EndHour,
(DATEPART(MINUTE, [EndTime])) AS EndMinute, StartTime, EndTime
FROM [test].[dbo].[Outage_Reports]
ORDER BY OutageDate ASC
Which produces:
StartHour StartMinute EndHour EndMinute Startime EndTime
16 0 17 30 16:00:00 17:30:00
I now need to write this conversion into a stored procedure that also inserts two (or more if the outage goes on for several hours) new rows into the table when the length between start and end is more than one hour. Or just inserts one row when the outage was below or equal to an hour. And then I need to account for that hourly progression in the start and end columns. Like this:
StartHour StartMinute EndHour EndMinute Startime EndTime
16 0 17 00 16:00:00 17:30:00
(the above reflects the first hour of outage, the second row below reflects the second half hour of the outage until it stopped...both will be tied to the same outage ticket in the table)
StartHour StartMinute EndHour EndMinute Startime EndTime
17 30 18 00 16:00:00 17:30:00
The idea is to track website outages hour by hour so they can join to an orders table that tracks orders by hour (and the orders never contain minutes...just hours). So the plan is to make two rows for an outage that goes on for 1.5 hours so the 16, 17 and all the way through the rounded up 18 hourly values can be tied to the orders table with the 30 minute column to act as another point of calculation (so an hour and a half would equal a full hour's worth of orders plus a half hour's worth of orders...split out row by row). This way I can better track trends during outages.
I'm a bit at a loss as to how to write this logic to a stored procedure. I would conceivably have to declare the new hour and minute values into variables and for the StartHour column always keep it rounded to the DATEPART hour value (even if it was 16:45...I want to insert 16 into the StartHour column). However, with the EndHour column, I want to insert a rounded up hourly value (17 and then 18 because we went over an hour in that case) into the EndHour column. This would hopefully describe (via these two rows) the close to two hours the outage occurred. And in turn it would allow for an easy join to our orders table
Any guidance on a stored procedure for this logic would be appreciated.
well, i didn't really understand the purpose!!
but the logic may be something like as below---
declare #StartTime time
declare #EndTime time
declare #Temp_StartTime time
declare #temp_StartHour int
declare #temp_EndHour int
declare #temp_StartMinute int
declare #temp_EndMinute int
SET #StartTime='2:30:00'
SET #EndTime='4:01:00'
SET #Temp_StartTime=#StartTime
SET #temp_StartHour=DATEPART(HOUR, #StartTime)
SET #temp_EndHour=DATEPART(HOUR, #EndTime)
SET #temp_StartMinute=DATEPART(MI, #StartTime)
SET #temp_EndMinute=DATEPART(MI, #EndTime)
if(#temp_EndMinute>0)
BEGIN
SET #temp_EndHour=#temp_EndHour+1
END
DECLARE #Temp_Table TABLE
(
StartHour int,
StartMinute int,
EndHour int,
EndMinute int,
StartTime time,
EndTime time
)
WHile((#temp_EndHour-#temp_StartHour>=1))
BEGIN
INSERT INTO #Temp_Table
SELECT (DATEPART(HOUR, #Temp_StartTime)) AS StartHour,(DATEPART(MINUTE, #Temp_StartTime)) AS StartMinute,
#temp_StartHour+1 AS EndHour,
0 AS EndMinute, #StartTime as StartTime, #EndTime as EndTime
SET #temp_StartHour=#temp_StartHour+1
SET #Temp_StartTime=DATEADD(HOUR,1,#Temp_StartTime)
if(DATEPART(MI, #Temp_StartTime)!=0)
BEGIN
SET #Temp_StartTime=DATEADD(MI,-#temp_StartMinute,#Temp_StartTime)
END
END
SELECT * FROM #Temp_Table
hope it'll help.
I need to find whether a new schedule overlaps any existing schedules.
This is the "intervals" table:
id first last
1 1900-01-01 09:00 1900-01-01 10:00
2 1900-01-01 15:00 1900-01-01 18:00
3 1900-01-01 18:01 1900-01-01 08:00
I am using a scalar function dbo.TimeOnly for extracting time part from the datetime fields.
My selection criteria as follows
First case
declare #start datetime
declare #end datetime
set #start = dbo.TimeOnly('2011-may-11 08:01:00');
set #end = dbo.TimeOnly('2011-may-11 15:30:00');
select * from intervals where
( NOT ( dbo.TimeOnly(last) < #start OR #end < dbo.TimeOnly(first) ) )
This will return 1st and 2nd records. I got this logic from Check whether the schedule overlaps each other?
Second case
set #start = dbo.TimeOnly('2011-may-11 07:01:00');
set #end = dbo.TimeOnly('2011-may-11 08:30:00');
How do I write a query that will return only the 3rd record for the criteria in the second case?
UPDATE
I will give more details for my problem
Different people are managing a particular event for a certain time duration in a day.
For Monday, the schedule format is like this
Id Start End User Days
1 00:01 AM 08:00 AM 'A' 1
2 08:01 AM 04:00 PM 'B' 1
3 04:00 PM 00:00 AM 'C' 1
For Tuesday's
4 08:01 AM 04:00 PM 'B' 2
5 07:00 PM 07:00 AM 'C' 2
For Wednesday's
6 08:01 AM 04:00 PM 'A' 4
7 10:00 PM 08:00 AM 'B' 4
Here days are stored in the bit value format ie
Monday=1,Tuesday=2,Wednesday=4,Thursday=8,Friday=16,Saturday=32 and Sunday=64
When we creating a schedule for a particular day, it should not overlap between times.
I would like to get a SQL query for checking any schedules exists while creating a new schedule for a particular day.
For a particular event time (Say An even occured at 04:00 AM on Tuesday) I would like to find the correct schedule (Will be "5") that falls between the Start and End time.
Change your SELECT to this:
select * from intervals where
(
( dbo.TimeOnly(last) > dbo.TimeOnly(first)
AND
NOT (dbo.TimeOnly(last) < #start OR #end < dbo.TimeOnly(first)) )
OR
( dbo.TimeOnly(last) < dbo.TimeOnly(first)
AND
( #start >= dbo.TimeOnly(first) OR #end <= dbo.TimeOnly(last) OR (#start < dbo.TimeOnly(first) AND #end > dbo.TimeOnly(last)) ) )
)
I might've missed a parenthesis somewhere, but I hope not.
The concept here is a query with 2 main groupings combined with an OR. The first clause checks intervals where last > first and is mainly a copy of your existing query with the addition of the last > first condition, while the 2nd clause checks intervals where last < first.
In the case where last < first, there are 3 ways that an interval can overlap:
start is after the interval's first
end is before the interval's last
start and end completely engulf the interval, i.e., start is before first and end is after last
Any one of these 3 conditions would mean the schedule to check is within an existing interval, so the 3 conditions are combined with ORs.
You will need to do something like this:
Declare #start datetime
Declare #duration int
Set #start = dbo.TimeOnly('2011-May-11 07:01:00');
-- Get the number of minutes in your timespan
Set #duration = DateDiff(minute, '2011-May-11 07:01:00', '2011-May-12 08:30:00');
Select id, first, last
From intervals
Where (DateDiff(minute, dbo.TimeOnly(first)), #start) + #duration) > 0
AND DateDiff(minute, dbo.TimeOnly(first), #start) <
DateDiff(minute, dbo.TimeOnly(first), dbo.TimeOnly(last));
Assuming that your dbo.TimeOnly function is essentially the same as Convert(time, {timefield}).
This will first find the difference between the new start time and the existing start times, then will find out if the duration of the new period is longer than that difference. This covers new periods that begin before or during existing ones.
The last clause compares the difference between the new start time and the existing start time to the duration of the existing period, to check whether the existing period is longer than the difference between them. Otherwise, the new start time will naturally be after the existing end time, which means it does not overlap.
I have a table with measures and the time this measures have been taken in the following form: MM/DD/YYYY HH:MI:SS AM. I have measures over many days starting at the same time every day.The datas are minute by minute so basically the seconds are always = 0. I want to select only the measures for the first 5 minutes of each day. I would have used the where statement but the condition would only be on the minutes and note the date is there a way to do this?
Thanks
You could try something like this:
SELECT * FROM SomeTable
WHERE
DATEPART(hh, timestamp_col) = 0 AND -- filter for first hour of the day
DATEPART(mm, timestamp_col) <= 5 -- filter for the first five minutes
Careful! 0 means midnight. If your "first hour" of the day is actually 8 or 9 AM then you should replace the 0 with an 8 or 9.