Используя отличную отправную точку Unreason, вот реализация TSQL для SQL Server 2012.
Этот первый SQL заполняет таблицу нашими рабочими днями и временем, исключая выходные и праздничные дни:
declare @dteStart date
declare @dteEnd date
declare @dtStart smalldatetime
declare @dtEnd smalldatetime
Select @dteStart = '2016-01-01'
Select @dteEnd = '2016-12-31'
CREATE TABLE working_hours (starttime SMALLDATETIME, endtime SMALLDATETIME);
while @dteStart <= @dteEnd
BEGIN
IF datename(WEEKDAY, @dteStart) <> 'Saturday'
AND DATENAME(WEEKDAY, @dteStart) <> 'Sunday'
AND @dteStart not in ('2016-01-01' --New Years
,'2016-01-18' --MLK Jr
,'2016-02-15' --President's Day
,'2016-05-30' --Memorial Day
,'2016-07-04' --Fourth of July
,'2016-09-05' --Labor Day
,'2016-11-11' --Veteran's Day
,'2016-11-24' --Thanksgiving
,'2016-11-25' --Day after Thanksgiving
,'2016-12-26' --Christmas
)
BEGIN
select @dtStart = SMALLDATETIMEFROMPARTS(year(@dteStart),month(@dteStart),day(@dteStart),8,0) --8:00am
select @dtEnd = SMALLDATETIMEFROMPARTS(year(@dteStart),month(@dteStart),day(@dteStart),17,0) --5:00pm
insert into working_hours values (@dtStart,@dtEnd)
END
Select @dteStart = DATEADD(day,1,@dteStart)
END
Теперь вот логика, которая работала, чтобы вернуть минуты как INT:
declare @event_start datetime2
declare @event_end datetime2
select @event_start = '2016-01-04 8:00'
select @event_end = '2016-01-06 16:59'
SELECT SUM(duration) as minutes
FROM
(
SELECT DATEDIFF(mi,@event_start,@event_end) as duration
FROM working_hours
WHERE @event_start >= starttime
AND @event_start <= endtime
AND @event_end <= endtime
UNION ALL
SELECT DATEDIFF(mi,@event_start,endtime)
FROM working_hours
WHERE @event_start >= starttime
AND @event_start <= endtime
AND @event_end > endtime
UNION ALL
SELECT DATEDIFF(mi,starttime,@event_end)
FROM working_hours
WHERE @event_end >= starttime
AND @event_end <= endtime
AND @event_start < starttime
UNION ALL
SELECT SUM(DATEDIFF(mi,starttime,endtime))
FROM working_hours
WHERE starttime > @event_start
AND endtime < @event_end
) AS u
Это корректно возвращает 1 минуту, застенчивую из трех 9-часовых рабочих дней