DATEDIFF in Business Working Hours & Days Only

别等时光非礼了梦想. 提交于 2021-02-20 04:55:27

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!