问题
I am trying to write a report and am a little stuck :/ I am trying to show the hours and minutes between two dates however minus the non business working hours.
Example a business works weekdays between 08:00 until 17:00 and a call was logged at 16:00 today and closed tomorrow at 16:00 so that would be 24 hours minus the business hours so would work out at 9 hours.
I have also created a seperate table which holds all the days of the years except weekends and the start of the business working day along with the end of the business working day. But I am still stuck with finding out the hours between without the non business hours.
Example data:
Call_Initiated - Call_Ended
10/05/2013 15:00 - 13/05/2013 13:00
Result I would like
Call_Initiated - Call_Ended - Time_To_Resolve
10/05/2013 15:00 - 13/05/2013 13:00 - 07
回答1:
I was just curious about your problem and made this.
Maybe not the best script, but it might give you some ideas on how to tackle the problem.
It is fully functional, but I generated the dates and you might want to use your day-table.
declare @callLogStart datetime = '2013-01-04 16:00'
declare @callLogEnd datetime = '2013-01-08 09:00'
;with dates(startDate, endDate)
as
(
select cast('2013-01-01 08:00' as datetime)
,cast('2013-01-01 17:00' as datetime)
union all
select DATEADD(day,1, startDate)
,DATEADD(day, 1, endDate)
from dates
where startDate < '2013-02-01 08:00'
)
,startDay
as
(
select *
,Datediff(hour, d.startDate, d.endDate) - DATEDIFF(hour, startDate, @callLogStart) as spent
from dates d
where @callLogStart between d.startDate and d.endDate
)
,endDay
as
(
select *
,Datediff(hour, d.startDate, d.endDate) - datediff(hour, @callLogEnd, endDate) as spent
from dates d
where @callLogEnd between d.startDate and d.endDate
)
select --SUM(spent) as actualTime
spent
,startDate
,endDate
,mark
from
(
select startDate
,endDate
,spent
,'start' as mark
from startDay
union
select startDate
,endDate
,spent
,'end'
from endDay
union
select s.startDate
,s.endDate
,-Datediff(hour, s.startDate, s.endDate)
,'remove'
from startDay s
join endDay e
on s.startDate = e.startDate
and s.endDate = e.endDate
union
select startDate
,endDate
,Datediff(hour, startDate, endDate)
,'between'
from dates
where @callLogStart < startDate
except
select startDate
,endDate
,Datediff(hour, startDate, endDate)
,'between'
from dates
where @callLogEnd < endDate
) x
order by
case mark
when 'start' then 0
when 'between' then 1
when 'end' then 2
when 'remove' then 3
end
Hope it helps
回答2:
This is a little simpler. Just a Single select statement. I broke each step down into it's own single column, so you could see how it was working. You only need the last column to figure out the hours though. It is dependent on locale since it uses datenames, but you could flip this out for day of week, so long as you know what DATEFIRST is set to.
Also, this doesn't include holidays. You'd have to create your own holiday table. I reference where you can link that into the final formula.
Just set the start and end date to whatever you want to play around with it, then to use it in your code, do a find/replace and replace those parameters with your field names. If you are using SQL Server 2008 or newer, you could simplify a lot of it by switching the open/close times to Time datatypes. Hope this helps!
declare @startDate datetime = '2013-09-05 10:45:00.000',
@endDate datetime = '2013-09-06 08:15:00.000',
@zeroDate datetime = '1900-01-01 00:00:00.000',
@businessOpen datetime = '1900-01-01 08:00:00.000',
@businessClose datetime = '1900-01-01 17:00:00.000',
@hoursOpen int;
select @hoursOpen = datediff(hour, @businessOpen, @businessClose);
select @hoursOpen as hoursOpen
, @endDate - @startDate as actualTimeCallOpen
, datediff(week, @startDate, @endDate) as wholeWeekendsCallOpen
, datediff(day, @startDate, @endDate) as daysCallOpen
, (DATEDIFF(dd, @StartDate, @EndDate)) --get days apart
-(DATEDIFF(wk, @StartDate, @EndDate) * 2) --subtract whole weekends from the date (*2 is for 2 days per weekend)
+(CASE WHEN DATENAME(dw, @StartDate) = 'Sunday' THEN 1 ELSE 0 END) --subtract the start date if it started on sunday (thus, partial weekend)
-(CASE WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN 1 ELSE 0 END) --subtract the end date if it ends on saturday (again, partial weekend)
as MthruFDaysOpen
, datediff(hour, @startDate, @endDate) as timeHoursCallOpen
, datediff(minute, @businessOpen, convert(datetime, '1900-01-01 ' + convert(varchar(8),@startDate,108))) / 60.0 as hoursOpenBeforeCall
, datediff(minute, convert(datetime, '1900-01-01 ' + convert(varchar(8), @endDate, 108)), @businessClose) / 60.0 as hoursOpenAfterCall
, (@hoursOpen - ((datediff(minute, convert(datetime, '1900-01-01 ' + convert(varchar(8), @endDate, 108)), @businessClose) + datediff(minute, @businessOpen, convert(datetime, '1900-01-01 ' + convert(varchar(8),@startDate,108)))) / 60.0)) as partialHourDay
, ( ((DATEDIFF(dd, @StartDate, @EndDate)) --get days apart,
- (DATEDIFF(wk, @StartDate, @EndDate) * 2) --subtract whole weekends from the date
+ (CASE WHEN DATENAME(dw, @StartDate) = 'Sunday' THEN 1 ELSE 0 END) --subtract the start date if it started on sunday (thus, partial weekend)
- (CASE WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN 1 ELSE 0 END) --subtract the end date if it ends on saturday (again, partial weekend)
--If you have a table with holidays in it, you can subtract the count of holidays from this as well
--test where the holiday is between startdate and end date and the holiday itself isn't a saturday or sunday
) * @hoursOpen) --multiply the whole days open times hours per day, giving us
+ (@hoursOpen --start with hours open
- ( -- then subtract the sum of hours the business was open before and after the call
(datediff(minute, convert(datetime, '1900-01-01 ' + convert(varchar(8), @endDate, 108)), @businessClose) --calculate this different in minutes for greater accuracy
+ datediff(minute, @businessOpen, convert(datetime, '1900-01-01 ' + convert(varchar(8),@startDate,108)))
) / 60.0) --divide by 60 to convert back to hours before subtracting from @hours open
) as businessTimeOpen
来源:https://stackoverflow.com/questions/16522577/datediff-in-business-working-hours-days-only