Рассчитать разницу во времени (только рабочие часы) в минутах между двумя датами - PullRequest
3 голосов
/ 21 июля 2010

Мне нужно рассчитать количество «активных минут» для события в базе данных.Время начала хорошо известно.

Сложность состоит в том, что эти активные минуты следует считать только в течение рабочего дня - с понедельника по пятницу с 9:00 до 18:30, исключая выходные и (известный) список праздничных дней

Начальное или «текущее» время может быть вне рабочих часов, но учитываются только рабочие часы.

Это SQL Server 2005, поэтому можно использовать T-SQL или управляемую сборку.

Ответы [ 5 ]

5 голосов
/ 21 июля 2010

Если вы хотите сделать это на чистом SQL, вот один из подходов

CREATE TABLE working_hours (start DATETIME, end DATETIME);

Теперь заполните таблицу рабочих часов счетными периодами, ~ 250 строк в год.

Если у вас есть событие(@event_start, @event_end), который будет начинаться с часов и заканчиваться часами, а затем будет достаточно простого запроса

SELECT SUM(end-start) as duration
FROM working_hours
WHERE start >= @event_start AND end <= @event_end

.

Если, с другой стороны, событие начинается и / или заканчивается во времярабочее время запрос более сложен

SELECT SUM(duration) 
FROM 
(
   SELECT SUM(end-start) as duration
   FROM working_hours
   WHERE start >= @event_start AND end <= @event_end
UNION ALL
   SELECT end-@event_start
   FROM working_hours
   WHERE @event_start between start AND end
UNION ALL
   SELECT @event_end - start
   FROM working_hours
   WHERE @event_end between start AND end
) AS u

Примечания:

  • приведенный выше запрос не прошел тестирование, в зависимости от вашей СУБД вам могут понадобиться функции даты / времени для агрегирования и вычитания даты и времени (и в зависимости от используемых функций вышеуказанный запрос может работать с любой точностью по времени).
  • запрос можно переписать, чтобы не использовать UNION ALL.
  • таблицу working_hours можно использовать для других целей в системе и обеспечивает максимальную гибкость

EDIT: В MSSQL вы можете использовать DATEDIFF (mi, start, end), чтобы получить количество минут для каждого вычитания выше.

2 голосов
/ 19 апреля 2016

Используя отличную отправную точку 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-часовых рабочих дней

1 голос
/ 10 октября 2013

Я начал работать с тем, что написал Unreason, и это было отличное начало.Я проверил это SQL Server и обнаружил, что не все время было захвачено.Я думаю, что проблема была в первую очередь, когда мероприятие началось и закончилось в тот же день.Это решение, кажется, работает достаточно хорошо для меня

Мой первый пост!Будь милостив.

1 голос
/ 06 апреля 2011

Я пришел сюда в поисках ответа на очень похожий вопрос - мне нужно было получить минуты между 2 датами, исключая выходные и исключая часы вне 08:30 и 18:00. После небольшого количества взлома, я думаю, что у меня это отсортировано. Ниже как я это сделал. мысли приветствуются - кто знает, может однажды я зарегистрируюсь на этом сайте:)

create function WorkingMinutesBetweenDates(@dteStart datetime, @dteEnd datetime)
returns int
as
begin

declare @minutes int
set @minutes = 0

while @dteEnd>=@dteStart
    begin

        if  datename(weekday,@dteStart) <>'Saturday' and  datename(weekday,@dteStart)<>'Sunday'
            and (datepart(hour,@dteStart) >=8 and datepart(minute,@dteStart)>=30 )
            and (datepart(hour,@dteStart) <=17)

            begin
                set @minutes = @minutes + 1
            end     

        set @dteStart = dateadd(minute,1,@dteStart)
    end

return @minutes
end
go
0 голосов
/ 21 июля 2010

В глобальном масштабе вам понадобится:

  1. Способ записи времени окончания события (возможно, посредством уведомления или любого другого события, которое изначально начало события) и таблица длязапишите это время начала и окончания.
  2. Вспомогательная таблица, содержащая все периоды (начало и конец), которые необходимо посчитать.(И тогда вам понадобится некоторый вспомогательный код, чтобы поддерживать эту таблицу в актуальном состоянии в будущем)
  3. Хранимая процедура, которая:
    • перебирает эту вспомогательную таблицу и находит «активный»периоды
    • рассчитывают минуты в каждом активном периоде.

(Обратите внимание, что это предполагает, что событие может длиться несколько дней: действительно ли это возможно?)

Другой способ заключался бы в том, чтобы тикать часы внутрисобытие, которое проверяет каждый раз, следует ли считать событие в это время, и увеличивается (в секундах или минутах) каждый раз, когда обнаруживает себя активным в течение соответствующего периода.Это все еще потребует вспомогательной таблицы и будет менее проверяемым (предположительно).

...