Как рассчитать разницу между двумя датами в секундах в рабочее время для рабочих дней SQL Server? - PullRequest
1 голос
/ 22 июня 2019

Мне нравится получать разницу в секундах между двумя рабочими днями в SQL Server. У нас есть таблица дат, содержащая флаг IsWorkingDay. Если конечная дата равна нулю, то по умолчанию она должна быть getdate (). Рабочий день начинается в 8 часов утра и заканчивается в 16:30.

У меня следующий запрос, нужна помощь в остальной части.

@ StartDate и @EndDate не всегда будут в рабочие дни. Если @StartDate в какие-либо выходные или праздничные дни, он должен быть перенесен на следующий рабочий день в 8:00. Если @EndDate в какие-либо выходные или праздничные дни, он должен быть свернут до последнего рабочего дня в 16:30.

CREATE FUNCTION TimeDiffInSeconds
(
    @Startdate DATETIME
    ,@EndDate DATETIME
)
RETURNS INT 
AS 
BEGIN
    DECLARE @WorkSeconds INT = 0;
    DECLARE @Reverse BIT;
    DECLARE @StartHour FLOAT = 8
    DECLARE @EndHour FLOAT = 16.50

    IF @Startdate > @EndDate
        BEGIN
            DECLARE @TempDate DATETIME = @Startdate;
            SET @Startdate = @EndDate;
            SET @EndDate = @TempDate;
            SET @Reverse = 1;
        END;
    ELSE 
        SET @Reverse = 0;


    IF DATEPART(HH, @StartDate) < @StartHour
        SET @StartDate = DATEADD(HOUR, @StartHour, DATEDIFF(DAY, 0, @StartDate)); 
    IF DATEPART(HH, @StartDate) >= @EndHour + 1
        SET @StartDate = DATEADD(HOUR, @StartHour + 24, DATEDIFF(DAY, 0, @StartDate));
    IF DATEPART(HH, @EndDate) >= @EndHour + 1
        SET @EndDate = DATEADD(HOUR, @EndHour, DATEDIFF(DAY, 0, @EndDate)); 
    IF DATEPART(HH, @EndDate) < @StartHour
        SET @EndDate = DATEADD(HOUR, @EndHour - 24, DATEDIFF(DAY, 0, @EndDate)); 

    IF @Startdate > @EndDate
    RETURN 0;


    IF DATEDIFF(DAY, @StartDate, @EndDate) <= 0
        BEGIN
            IF @Startdate <> (SELECT date_id FROM Final.Date WHERE IsWorkingDay = 0)
                SET @WorkSeconds = DATEDIFF(ss, @StartDate, @EndDate); -- Calculate difference
            ELSE RETURN 0;
        END;
    ELSE 

    --need help




RETURN @WorkSeconds;
END 

1 Ответ

1 голос
/ 22 июня 2019

Можно рассчитать простым способом.

Если ваши два параметра уже являются рабочими днями, вы можете просто вернуть их разницу в секундах, минус 15,5 часа (с 16:30 до 08:00) для разницы каждого дня (каждый раз, когда пересекается граница полуночи),минус 8,5 часов (с 8:00 до 16:30) за каждый нерабочий день между вашими двумя датами.

PS: я обновил ответ, поэтому теперь мы сначала проверим, являются ли @StartDate и @EndDateправильные рабочие даты, а если нет, то мы перемещаем их в правильные.После этого вы можете применить ранее описанный расчет для рабочего времени в секундах.

CREATE FUNCTION TimeDiffInSeconds
(
    @Startdate datetime,
    @EndDate datetime
)
RETURNS INT 
AS 
BEGIN   
  set @EndDate = coalesce(@EndDate, getdate());

  -- We check that @StartDate is a working datetime, and if not we set it to the next one      

  if convert(time, @StartDate) < convert(time, '08:00') 
  begin
    set @StartDate = convert(datetime, convert(date, @StartDate)) + 
                     convert(datetime, '08:00')
  end   
  if convert(time, @StartDate) > convert(time, '16:30') or
     (select IsWorkingDay 
      from Final.Date 
      where date_id = convert(date, @StartDate)) = 0 
  begin
    select top 1 @StartDate = convert(datetime, date_id) + 
                              convert(datetime, '08:00')
    from Final.Date
    where date_id > @StartDate and IsWorkingDay = 1  
    order by date_id 
  end     

  -- We check that @EndDate is a working datetime, and if not we set it to the last one      

  if convert(time, @EndDate) > convert(time, '16:30') 
  begin
    set @EndDate = convert(datetime, convert(date, @EndDate)) + 
                   convert(datetime, '16:30')
  end   
  if convert(time, @EndDate) < convert(time, '08:00') or
     (select IsWorkingDay 
      from Final.Date 
      where date_id = convert(date, @EndDate)) = 0 
  begin
    select top 1 @EndDate = convert(datetime, date_id) + 
                            convert(datetime, '16:30')
    from Final.Date
    where date_id < @EndDate and IsWorkingDay = 1 
    order by date_id desc   
  end     

  -- We return the working time difference in seconds between @StartDate and @EndDate

  RETURN datediff(second, @StartDate, @EndDate) -    
     ((15.5 * datediff(day, @StartDate, @EndDate) * 60 * 60) -
      (8.5 * (select count(*) 
              from Final.Date 
              where IsWorkingDay = 0 and
                   (date_id between @StartDate and @EndDate or date_id between @EndDate and @StartDate)
             ) * 60 * 60));
END

Тест онлайн: https://rextester.com/FWR14059

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...