How to calculate business hours/minutes between two dates? - sql

I'm trying to understand how to calculate business hours between 7PM and 7AM.
For Example I have:
Start time: 2018-01-10 19:15:00
End time: 2018-01-11 09:00:00
I expect calculation to return (11:45:00) between 7PM and 7AM.

Your requirements are not very clear, however this should be a good query to start from:
declare #tmp table(StartTime datetime, EndTime datetime)
insert into #tmp values
('2018-07-01 19:35:00', '2018-07-01 21:55:00')
,('2018-08-01 12:35:00', '2018-08-01 21:55:00')
,('2018-08-01 12:35:00', '2018-08-02 05:55:00')
,('2018-08-01 12:35:00', '2018-08-02 07:00:00')
,('2018-08-01 12:35:00', '2018-08-02 07:15:00')
SELECT StartTime
,EndTime
,CASE
WHEN StartTime < dateadd(HOUR, 19, cast(cast(StartTime AS DATE) AS DATETIME))
THEN convert(VARCHAR(5), dateadd(minute, datediff(MINUTE, dateadd(HOUR, 19, cast(cast(StartTime AS DATE) AS DATETIME)),
CASE
WHEN endtime < DATEADD(HOUR, 7, cast(DATEADD(day, 1, cast(StartTime AS DATE)) AS DATETIME))
THEN endtime
ELSE DATEADD(HOUR, 7, cast(DATEADD(day, 1, cast(StartTime AS DATE)) AS DATETIME))
END), 0), 114)
ELSE NULL
END AS Extra_time
FROM #tmp
Results with different test cases:
Note: extra time is capped at 12:00 because you want working hours between 7PM and 7AM
Note 2: extra time is computed only if Start time is before 7 PM because in comments you wrote: "I need only extra hours after 7 PM if Start time before 7 PM"

Related

Combining Date and Time using DATEADD and DATEDIFF

I'm trying to create a new column by combining the date and time variables. For example, the data table looks like this and "StartDateTime" is the new variable I want to create.
Date StartTime *StartDateTime*
2014-03-20 1900-01-01 10:00:00.000 2014-03-30 10:00:00.000
2015-09-23 1900-01-01 11:00:00.000 2015-09-23 11:00:00.000
I used the cast function and it seems like my current code is working.
select *,
(cast(Date as datetime) + cast(StartTime as datetime)) as StartDateTime
from my_table
But I just saw this line of code on a random website and it seems like it does the same thing. However, I didn't really get the logic behind it.
select *,
DATEADD(day, 0, DATEDIFF(day, 0, Date)) + DATEADD(day, 0 -DATEDIFF(day, 0, StartTime), StartTime) As StartDateTime
from my_table
I believe the first part DATEADD(day, 0, DATEDIFF(day, 0, Date)) just returns the original date but I don't really get the second part. My understanding is DATEDIFF(day, 0, StartTime) would just return 0 and I'm not sure why 0 -DATEDIFF(day, 0, StartTime) is necessary.
Thank you.
This is one way to combine the date and time values into a single DateTime2:
declare #Samples as Table ( StartDate Date, StartTime DateTime2 );
insert into #Samples ( StartDate, StartTime ) values
( '2014-03-20', '1900-01-01 10:00:00.000' ),
( '2015-09-23', '1900-01-01 11:00:00.000' );
select StartDate, StartTime,
-- Demonstrate how to get the time with millisecond resolution from StartTime .
Cast( StartTime as Time(3) ) as StartTimeAsTime,
-- Combine the time from StartTime with the date from StartDate .
-- Get the time, convert it to milliseconds after midnight, and add it to the date as a DateTime2 .
DateAdd( ms, DateDiff( ms, 0, Cast( StartTime as Time(3) ) ), Cast( StartDate as DateTime2 ) ) as StartDateTime
from #Samples;
I have no idea what that code is doing. And the add operator is also not supported by all datetime datatypes. The correct solution is:
select *
, dateadd(second, datepart(second, StartTime), dateadd(minute, datepart(minute, StartTime), dateadd(hour, datepart(hour, StartTime), [Date])))
from (values (convert(datetime2(0),'2014-03-20'), convert(time,'10:00:00.000'))) as X ([Date], StartTime);
Ideally you would store your StartTime value in a time datatype. But the above code will still work with a datetime2 datetype (which is the recommended form of datetime to use).

available room booking between two dates and and two times column sql server

i have four columns in my table.
STARTDATE STARTTIME ENDDATE ENDTIME ROOMCODE
2018-10-16 00:00:00.000 14:00 2018-10-16 00:00:00.000 18:00 CS0001
2018-10-16 00:00:00.000 18:00 2018-10-16 00:00:00.000 22:00 CS0001
i want to check booking is available or not
select CONFERENCE_ROOM from COR_CONFERENCE_BOOKING where
(cast(STARTDATE as datetime) + cast(START_TIME as time) >= cast('2018-10-16'
as datetime) + cast(DATEADD(MINUTE, 01, '14:00') as time)
and cast(STARTDATE as datetime) + cast(START_TIME as time) < cast('2018-10-
16' as datetime) + cast('18:00' as time))
or (cast(ENDDATE as datetime) + cast(END_TIME as time) >= cast('2018-10-16'
as datetime) + cast(DATEADD(MINUTE, 01, '14:00') as time)
and cast(ENDDATE as datetime) + cast(END_TIME as time) < cast('2018-10-16'
as datetime) + cast('18:00' as time))
and CONFERENCE_ROOM='CS0001'
problem is there i want to select the data if any data found on select query on passing date and time then room is booked otherwise its free.
please solve this query. Its too complicated for me.
Here's an example snippet for MS SQL Server.
I'm assuming that this is your target RDBMS because the example SQL uses that DATEADD function.
It'll only return the first record from the table variable.
Because the second record is out of the range.
declare #Table table (
ID INT PRIMARY KEY IDENTITY(1,1),
STARTDATE date,
STARTTIME time,
ENDDATE date,
ENDTIME time,
CONFERENCE_ROOM varchar(6)
);
insert into #Table (STARTDATE, STARTTIME, ENDDATE, ENDTIME, CONFERENCE_ROOM) values
('2018-10-16','14:00:00','2018-10-16','18:00:00','CS0001'),
('2018-10-16','18:00:00','2018-10-16','22:00:00','CS0001');
select ID, CONFERENCE_ROOM
from #Table t
where (CAST(STARTDATE AS DATETIME) + CAST(STARTTIME as DATETIME)) < (CAST(ENDDATE AS DATETIME) + CAST(ENDTIME as DATETIME))
and (CAST(STARTDATE AS DATETIME) + CAST(STARTTIME as DATETIME)) >= CAST('2018-10-16 14:00' AS DATETIME)
and (CAST(ENDDATE AS DATETIME) + CAST(ENDTIME as DATETIME)) <= CAST('2018-10-16 18:00' AS DATETIME)
and CONFERENCE_ROOM = 'CS0001';
If the STARTTIME & ENDTIME are VARCHAR's instead of TIME data types?
Then to avoid errors with trying to convert crap data, you could use TRY_CAST instead.
(If TRY_CAST is available on your version of MS SQL Server)
Because instead of an error a TRY_CAST would return NULL when the conversion fails.
Example:
select ID, CONFERENCE_ROOM
from #Table t
where STARTDATE = ENDDATE
and TRY_CAST(STARTTIME AS TIME) < TRY_CAST(ENDTIME AS TIME)
and STARTDATE = CAST('2018-10-16' AS DATE)
and TRY_CAST(STARTTIME AS TIME) >= CAST('14:00' AS TIME)
and TRY_CAST(ENDTIME AS TIME) <= CAST('18:00' AS TIME)
and CONFERENCE_ROOM = 'CS0001';

to get visits having end time between 20:00 to midnight (00:00)

from the table below, I need to get the visits which having EndTime between 20:00 to 00:00. (highlighted in yellow)
this is the query I am using now, but if I am not getting any result. if I change the time 00:00 to 23:59, I am getting the other two results, but not the one with endtime = 00:00.
Select VisitID, StartTime, duration, dateadd(minute,Duration,StartTime) as EndTime
from visit
where StartTime between '2018-02-01' and '2018-02-02 23:59'
and cast(dateadd(minute,Duration,StartTime) as Time) >= '20:00'
and cast(dateadd(minute,Duration,StartTime) as Time) <= '00:00'
Please assist. thanks.
You don't get any result as TIME 00:00 is earlier than 20:00
Checks for 20:00 and 23:59 with a OR condition for 00:00
AND
(
cast(dateadd(minute,Duration,StartTime) as Time) BETWEEN '20:00' AND '23:59'
OR cast(dateadd(minute,Duration,StartTime) as Time) = '00:00'
)
For getting data between two dates, I will not prefer BETWEEN clause. We can do this using >= and <= operators as shown below -
declare #visit table (visitid uniqueidentifier, StartTime datetime, duration int)
insert into #visit
select newid(), '2018-02-01 19:00:00', 60
union all
select newid(), '2018-02-01 20:00:00', 240
union all
select newid(), '2018-02-01 21:00:00', 120
Select VisitID, StartTime, duration, dateadd(minute,Duration,StartTime) as EndTime
from #visit
where
dateadd(minute,Duration,StartTime) >= '2018-02-01 20:00:00'
and dateadd(minute,Duration,StartTime) <= '2018-02-02 00:00:00'
The only issue I have seen is that you are using an AND instead of an OR.
Select VisitID, StartTime, duration, dateadd(minute,Duration,StartTime) as EndTime
from visit
where StartTime between '2018-02-01' and '2018-02-02 23:59'
and (cast(dateadd(minute,Duration,StartTime) as Time) >= '20:00'
or cast(dateadd(minute,Duration,StartTime) as Time) <= '00:00')

The correct if statement with and in this situation in SQL Server

I got this data in my database
id shift_no time_in time_out
---------------------------------------
1 Shift 1 06:00:00 14:00:00
2 Shift 2 14:00:00 22:00:00
3 Shift 3 22:00:00 06:00:00
So I got this date:
convert(time(0),dateadd(HOUR, 15, getdate()), 108)
I want to get only the shift that is within the range of this time convert(time(0), dateadd(HOUR, 15, getdate()), 108)
Sorry for an answer, but I'm not able to comment quite yet...this is comment for Tanner's answer.
Can you try splitting the 3rd shift entry:
INSERT INTO #shifts
(
shiftNo,
time_In,
time_Out
)
VALUES
(1, '06:00:00', '14:00:00'),
(2, '14:00:00', '22:00:00'),
(3, '22:00:00', '23:59:59'),
(3, '00:00:00', '06:00:00');
-- the selected time
SELECT CONVERT(TIME(0), DATEADD(HOUR, 15, GETDATE()), 108);
-- filter your shifts
SELECT *
FROM #shifts AS s
WHERE CONVERT(TIME(0), DATEADD(HOUR, -6, GETDATE()), 108)
BETWEEN s.time_In AND s.time_Out;
DROP TABLE #shifts;
You can use BETWEEN with your in and out times like so (note the below is re-runnable):
CREATE TABLE #shifts
(
shiftNo INT,
time_In TIME(0),
time_Out TIME(0)
);
INSERT INTO #shifts
(
shiftNo,
time_In,
time_Out
)
VALUES
(1, '06:00:00', '14:00:00'),
(2, '14:00:00', '22:00:00'),
(3, '22:00:00', '06:00:00');
-- the selected time
DECLARE #selectedTime TIME(0) = CONVERT(TIME(0), DATEADD(HOUR, 12, GETDATE()), 108);
-- modify the selected time if it falls in the shift that crosses midnight
SET #selectedTime = CASE WHEN #selectedTime > '22:00:00' OR #selectedTime < '06:00:00'
THEN '22:01:00' -- modified value
ELSE #selectedTime -- regular value
END;
-- show the time we are working with
SELECT #selectedTime;
-- filter your shifts
SELECT *
FROM #shifts AS s
WHERE #selectedTime
BETWEEN s.time_In AND CASE WHEN s.time_Out = '06:00:00' -- is the out time 6.00
THEN '23:59:59' -- change it to before midnight if so
ELSE s.time_Out -- keep the time as it is
END;
DROP TABLE #shifts;
The CASE statements in the queries work out if the times you are working with #selectedTime is a time that will cross over midnight before s.time_Out they are both adjusted, which allows the last shift to be selected.
There is probably a simpler solution, but this works with the data you have provided.
select
*
from yourtable
where
time_in between getdate() and convert(time(0),dateadd(HOUR, 15, getdate()), 108)
or time_out between getdate() and convert(time(0),dateadd(HOUR, 15, getdate()), 108)

Fetching record of last 48 hrs from SQL

I have table1 with with the columns DATETIME, ID and Status.
I will call my stored procedure after specific hours and I want to fetch records of last 48 non weekend hours.
I tried to do it by writing case for each day of getdate().
I want to know what is the best way to do this.
To avoid weekends, you can use a case or other logic in the where. Your logic isn't 100% clear on what to do on weekend days. But here is an approach:
where (datename(wk, getdate()) in ('Sunday', 'Monday', 'Tuesday') and datetime >= dateadd(hour, 48 + 48, getdate()) ) or
(datename, wk, getdate()) in ('Wednesday', 'Thursday', 'Friday') and datetime >= dateadd(hour, 48, getdate()) or
(datename , wk, getdate()) in ('Saturday') and datetime >= dateadd(hour, 24 + 48, getdate());