Sql server TSQL函数,用于查找两个日期之间的差异,同时考虑周末和节假日
发布了对现有SO问题的出色回复: 这几乎对我有效,但我需要计算两个日期之间的营业时间差,不包括周末,即使过去不到一周。我的解决方案添加了一个while循环(这可能有点幼稚,可以接受建议!),并在假日查找表中添加假日检查 编辑: 我并不是在寻找传统意义上的答案,我只是想简单地回到这个问题上,并把它打开,供将来可能遇到它的人批评Sql server TSQL函数,用于查找两个日期之间的差异,同时考虑周末和节假日,sql-server,tsql,datetime,Sql Server,Tsql,Datetime,发布了对现有SO问题的出色回复: 这几乎对我有效,但我需要计算两个日期之间的营业时间差,不包括周末,即使过去不到一周。我的解决方案添加了一个while循环(这可能有点幼稚,可以接受建议!),并在假日查找表中添加假日检查 编辑: 我并不是在寻找传统意义上的答案,我只是想简单地回到这个问题上,并把它打开,供将来可能遇到它的人批评 ALTER FUNCTION dbo.udfDateDiffBusinessHours ( @date1 DATETIME, @date2 DATETIME )
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时,我遇到了以下解决方案: 它使用的是一个工作日历表,您可以根据自己的意愿对其进行调整,以标记工作日(包括节假日) 计算营业时间将查询:
- 开始和结束日期之间的工作日,不包括开始和结束日期*(工作小时/天)
- +开工日的工作时间(如果是工作日)
- +结束日的工作时间(如果是工作日)