商务工作时间的DATEDIFF&只有几天

时间:2013-05-13 12:54:28

标签: tsql datediff

我正在尝试撰写报告并且有点卡住:/我试图显示两个日期之间的小时和分钟,但是减去非营业时间。

例如,工作日在08:00至17:00之间工作,并且电话记录在今天16:00,明天在16:00关闭,这将是24小时减去工作时间,因此将在9小时工作

我还创建了一个单独的表格,其中包含了除了周末和业务工作日开始以及业务工作日结束之外的所有年份。但我仍然坚持找到没有非工作时间的时间。

示例数据:

Call_Initiated - Call_Ended
10/05/2013 15:00 - 13/05/2013 13:00

结果我想要

Call_Initiated - Call_Ended - Time_To_Resolve
10/05/2013 15:00 - 13/05/2013 13:00 - 07

2 个答案:

答案 0 :(得分:2)

这有点简单。只需一个选择语句。我把每一步都打破了它自己的单列,所以你可以看到它是如何工作的。您只需要最后一列来计算小时数。它依赖于语言环境,因为它使用日期名称,但只要您知道DATEFIRST设置为什么,就可以将其翻转为星期几。

此外,这不包括假期。你必须创建自己的假期表。我参考了你可以将它链接到最终公式的地方。

只需将开始日期和结束日期设置为您要使用它的任何内容,然后在代码中使用它,执行查找/替换并将这些参数替换为您的字段名称。如果您使用的是SQL Server 2008或更高版本,则可以通过将打开/关闭时间切换为Time数据类型来简化大量操作。希望这有帮助!

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

答案 1 :(得分:0)

我只是对你的问题感到好奇并做了这件事。

也许不是最好的剧本,但它可能会给你一些关于如何解决这个问题的想法。

它功能齐全,但我生成了日期,您可能想要使用日历表。

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

希望有所帮助