如何在工作日内SQL Server的工作时间内以秒为单位计算两个日期之间的差异?

时间:2019-06-22 02:46:55

标签: sql sql-server tsql

我希望在SQL Server中获得两个工作日之间以秒为单位的差异。我们的日期表包含IsWorkingDay标志,如果结束日期为null,则默认为getdate()。工作日开始于上午8点,结束于下午4:30。

我有以下查询,需要其他部分的帮助。

@StartDate和@EndDate并不总是在工作日。如果@StartDate在任何周末或假日,则应汇总到下一个工作日的上午8:00。如果@EndDate在任何周末或假日,则应累积到最后一个工作日下午4: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 个答案:

答案 0 :(得分:1)

可以用一种简单的方法来计算。

如果您的两个参数已经是工作日,则您可以按秒返回它们的差异,即每天的差异(每次越过午夜边界)减去-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