Это немного проще. Просто оператор Single select. Я сломал каждый шаг в отдельный столбец, чтобы вы могли видеть, как он работает. Однако вам нужен только последний столбец, чтобы выяснить часы. Он зависит от языкового стандарта, поскольку он использует имена данных, но вы можете перевернуть его в течение дня, пока вы знаете, для чего установлен 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
Спасибо, Йохан, у меня будет gander :) –