Sql server TSQL函数,用于查找两个日期之间的差异,同时考虑周末和节假日

Sql server TSQL函数,用于查找两个日期之间的差异,同时考虑周末和节假日,sql-server,tsql,datetime,Sql Server,Tsql,Datetime,发布了对现有SO问题的出色回复: 这几乎对我有效,但我需要计算两个日期之间的营业时间差,不包括周末,即使过去不到一周。我的解决方案添加了一个while循环(这可能有点幼稚,可以接受建议!),并在假日查找表中添加假日检查 编辑: 我并不是在寻找传统意义上的答案,我只是想简单地回到这个问题上,并把它打开,供将来可能遇到它的人批评 ALTER FUNCTION dbo.udfDateDiffBusinessHours ( @date1 DATETIME, @date2 DATETIME )

发布了对现有SO问题的出色回复:

这几乎对我有效,但我需要计算两个日期之间的营业时间差,不包括周末,即使过去不到一周。我的解决方案添加了一个while循环(这可能有点幼稚,可以接受建议!),并在假日查找表中添加假日检查

编辑: 我并不是在寻找传统意义上的答案,我只是想简单地回到这个问题上,并把它打开,供将来可能遇到它的人批评

ALTER FUNCTION dbo.udfDateDiffBusinessHours (
  @date1 DATETIME,
  @date2 DATETIME
) RETURNS DATETIME AS
BEGIN
  DECLARE @sat INT
  DECLARE @sun INT
  DECLARE @workday_s INT
  DECLARE @workday_e INT
  DECLARE @basedate1 DATETIME
  DECLARE @basedate2 DATETIME
  DECLARE @calcdate1 DATETIME
  DECLARE @calcdate2 DATETIME
  DECLARE @iteratordate DATETIME
  DECLARE @cworkdays INT
  DECLARE @coffdays INT
  DECLARE @returnval INT

  SET @workday_s = 480 -- work day start:  8 hours
  SET @workday_e = 1080 -- work day end:   18 hours

    -- calculate Saturday and Sunday dependent on SET DATEFIRST option
  SET @sat = CASE @@DATEFIRST WHEN 7 THEN 7 ELSE 7 - @@DATEFIRST END 
  SET @sun = CASE @@DATEFIRST WHEN 7 THEN 1 ELSE @sat + 1 END 

  SET @calcdate1 = @date1
  SET @calcdate2 = @date2

  -- @date1: assume next day if start was after end of workday
  SET @basedate1 = DATEADD(dd, 0, DATEDIFF(dd, 0, @calcdate1))
  SET @calcdate1 = CASE WHEN DATEDIFF(mi, @basedate1, @calcdate1) > @workday_e
                   THEN @basedate1 + 1
                   ELSE @calcdate1
                   END

  -- @date1: if Saturday or Sunday, make it next Monday
  SET @basedate1 = DATEADD(dd, 0, DATEDIFF(dd, 0, @calcdate1))
  SET @calcdate1 = CASE DATEPART(dw, @basedate1)
                   WHEN @sat THEN @basedate1 + 2
                   WHEN @sun THEN @basedate1 + 1
                   ELSE @calcdate1
                   END

  -- @date1: assume @workday_s as the minimum start time
  SET @basedate1 = DATEADD(dd, 0, DATEDIFF(dd, 0, @calcdate1))
  SET @calcdate1 = CASE WHEN DATEDIFF(mi, @basedate1, @calcdate1) < @workday_s 
                   THEN DATEADD(mi, @workday_s, @basedate1)
                   ELSE @calcdate1
                   END

  -- @date2: assume previous day if end was before start of workday
  SET @basedate2 = DATEADD(dd, 0, DATEDIFF(dd, 0, @calcdate2))
  SET @calcdate2 = CASE WHEN DATEDIFF(mi, @basedate2, @calcdate2) < @workday_s
                   THEN DATEADD(mi, @workday_e, @basedate2 - 1)
                   ELSE @calcdate2
                   END

  -- @date2: if Saturday or Sunday, make it previous Friday
  SET @basedate2 = DATEADD(dd, 0, DATEDIFF(dd, 0, @calcdate2))
  SET @calcdate2 = CASE DATEPART(dw, @calcdate2)
                   WHEN @sat THEN @basedate2 - 0.00001
                   WHEN @sun THEN @basedate2 - 1.00001
                   ELSE @date2
                   END

  -- @date2: assume @workday_e as the maximum end time
  SET @basedate2 = DATEADD(dd, 0, DATEDIFF(dd, 0, @calcdate2))
  SET @calcdate2 = CASE WHEN DATEDIFF(mi, @basedate2, @calcdate2) > @workday_e
                   THEN DATEADD(mi, @workday_e, @basedate2)
                   ELSE @calcdate2
                   END

  -- count full work days (subtract Saturdays, Sundays and holidays)
  SET @cworkdays = DATEDIFF(dd, @basedate1, @basedate2)
  SET @iteratordate = @basedate1
  SET @coffdays = 0

  WHILE DATEDIFF(dd, @iteratordate, @basedate2) > 0
  BEGIN
    IF DATEPART(dw, @iteratordate) = @sat OR DATEPART(dw, @iteratordate) = @sun OR EXISTS (SELECT holidaydate FROM dbo.holidays_lu (NOLOCK) WHERE holidaydate = @iteratordate)
        SET @coffdays = @coffdays + 1
    SET @iteratordate = DATEADD(dd, 1, @iteratordate)
  END
  SET @cworkdays = @cworkdays - @coffdays

  -- calculate effective duration in minutes
  SET @returnval = @cworkdays * (@workday_e - @workday_s)
                   + @workday_e - DATEDIFF(mi, @basedate1, @calcdate1) 
                   + DATEDIFF(mi, @basedate2, @calcdate2) - @workday_e

  -- return duration as an offset in minutes from date 0
  RETURN DATEADD(mi, @returnval, 0)
END
ALTER函数dbo.udfDateDiffBusinessHours(
@日期1日期时间,
@日期2日期时间
)将日期时间返回为
开始
声明@sat INT
声明@sun INT
声明@workday\u INT
声明@workday_e INT
声明@basedate1 DATETIME
声明@basedate2 DATETIME
声明@calcdate1 DATETIME
声明@calcdate2 DATETIME
声明@IteratorDateTime
声明@cworkdays INT
声明@coffdays INT
声明@returnval INT
设置@workday_s=480——工作日开始时间:8小时
设置@workday_e=1080——工作日结束:18小时
--根据设置的日期优先选项计算星期六和星期日
设置@sat=CASE@@DATEFIRST WHEN 7然后7 ELSE 7-@@DATEFIRST END
将@sun=CASE@@DATEFIRST设置为7时,然后设置为1时@sat+1结束
设置@calcdate1=@date1
SET@calcdate2=@date2
--@date1:假设第二天开始时间在工作日结束后
SET@basedate1=DATEADD(dd,0,DATEDIFF(dd,0,@calcdate1))
设置@calcdate1=DATEDIFF(mi、@basedate1、@calcdate1)>@workday\u e时的大小写
然后@basedate1+1
ELSE@calcdate1
结束
--@date1:如果是周六或周日,就定在下周一
SET@basedate1=DATEADD(dd,0,DATEDIFF(dd,0,@calcdate1))
SET@calcdate1=CASE DATEPART(dw,@basedate1)
当@sat时,然后@basedate1+2
当@sun然后@basedate1+1时
ELSE@calcdate1
结束
--@date1:假设@workday_s为最短开始时间
SET@basedate1=DATEADD(dd,0,DATEDIFF(dd,0,@calcdate1))
设置@calcdate1=DATEDIFF(mi、@basedate1、@calcdate1)时的大小写
然后添加日期(mi、@workday\s、@basedate1)
ELSE@calcdate1
结束
--@date2:假设前一天结束时间在工作日开始之前
SET@basedate2=DATEADD(dd,0,DATEDIFF(dd,0,@calcdate2))
设置@calcdate2=DATEDIFF(mi、@basedate2、@calcdate2)时的大小写
然后添加日期(mi,@workday_e,@basedate2-1)
ELSE@calcdate2
结束
--@date2:如果是星期六或星期天,就定在前一个星期五
SET@basedate2=DATEADD(dd,0,DATEDIFF(dd,0,@calcdate2))
SET@calcdate2=CASE DATEPART(dw,@calcdate2)
当@sat时,则@basedate2-0.00001
当@sun然后@basedate2-1.00001
ELSE@date2
结束
--@date2:假设@workday_e为最长结束时间
SET@basedate2=DATEADD(dd,0,DATEDIFF(dd,0,@calcdate2))
设置@calcdate2=DATEDIFF(mi、@basedate2、@calcdate2)>@workday_e时的大小写
然后添加日期(mi、@workday_e、@basedate2)
ELSE@calcdate2
结束
--计算完整工作日(减去周六、周日和节假日)
设置@cworkdays=DATEDIFF(dd、@basedate1、@basedate2)
SET@iteratordate=@basedate1
设置@coffdays=0
而DATEDIFF(dd,@iteratordate,@basedate2)>0
开始
如果DATEPART(dw,@iteratordate)=@sat或DATEPART(dw,@iteratordate)=@sun或存在(从dbo.holidays_lu(NOLOCK)中选择holidaydate,其中holidaydate=@iteratordate)
设置@coffdays=@coffdays+1
SET@iteratordate=DATEADD(dd,1,@iteratordate)
结束
设置@cworkdays=@cworkdays-@coffdays
--以分钟为单位计算有效持续时间
设置@returnval=@cworkdays*(@workday\u e-@workday\u s)
+@workday_e-DATEDIFF(mi、@basedate1、@calcdate1)
+DATEDIFF(mi、@basedate2、@calcdate2)-@workday\u e
--将持续时间作为从日期0开始的偏移量返回(以分钟为单位)
返回日期添加(mi,@returnval,0)
结束

在搜索internet时,我遇到了以下解决方案:

它使用的是一个工作日历表,您可以根据自己的意愿对其进行调整,以标记工作日(包括节假日)

计算营业时间将查询:

  • 开始和结束日期之间的工作日,不包括开始和结束日期*(工作小时/天)
  • +开工日的工作时间(如果是工作日)
  • +结束日的工作时间(如果是工作日)

也许还可以将工作时间编码到工作日历表中,但我还没有尝试过。

在搜索internet时,我遇到了以下解决方案:

它使用的是一个工作日历表,您可以根据自己的意愿对其进行调整,以标记工作日(包括节假日)

计算营业时间将查询:

  • 开始和结束日期之间的工作日,不包括开始和结束日期*(工作小时/天)
  • +开工日的工作时间(如果是工作日)
  • +结束日的工作时间(如果是工作日)
也许也可以将工作时间编码到工作日历表中,但我还没有尝试过