【发布时间】:2015-03-07 04:23:28
【问题描述】:
希望有人能告诉我哪里出了问题,我从Calculate business hours between two dates 找到的营业时间查询开始,这是第二个最佳答案,因为最佳答案在测试时没有提供正确的输出。我遇到的问题是当我跨越到新的一天并且结束日期时间超过工作日结束时。这是我的测试:
选择 dbo.BusinessSeconds('09:00:00','17:00:00','2014-12-24 16:59:59','2014-12-26 18:00:00') ;
因此,如果我从 COB 前 1 秒到第二天开始,我得到 1 秒,这是正确的。如果我从同一天开始到第二天结束,我得到 28801,即 1 天零 1 秒——这也是正确的。但是,如果我将日期结束时间延长到 17:00:01 到 17:59:59,它还包括那些秒,但是如果我达到 18:00:00,则时间会截断回原来的 17:00:00 结束日。因此,我将获得任何给定结束时间的正确数据,除非它是在 17:00:00-17:59:59 时间范围内,然后我可能会得到一个我不应该有的额外时间。
任何帮助都将不胜感激,因为我明天有一个可交付成果。
ALTER Function [dbo].[BusinessSeconds](@BusinessDayStart TIME,@BusinessDayEnd TIME,@StartDate DATETIME,@EndDate DATETIME) Returns Int
AS
Begin
--TEST: select dbo.BusinessSeconds('09:00:00','17:00:00','2014-12-24 16:59:59','2014-12-26 18:00:00');
Declare @WorkMin INT = 0 -- Initialize counter
Declare @Reverse BIT -- Flag to hold if direction is reverse
Declare @StartHour TIME = @BusinessDayStart -- Start of business hours (can be supplied as an argument if needed)
Declare @EndHour TIME = @BusinessDayEnd -- End of business hours (can be supplied as an argument if needed)
Declare @Holidays Table (HDate DateTime) -- Table variable to hold holidayes
-- If dates are in reverse order, switch them and set flag
If @StartDate>@EndDate
Begin
Declare @TempDate DateTime=@StartDate
Set @StartDate=@EndDate
Set @EndDate=@TempDate
Set @Reverse=1
End
Else Set @Reverse = 0
-- Get country holidays from table based on the country code (Feel free to remove this or modify as per your DB schema)
-- Insert Into @Holidays(HDate) select DATEADD(month,((LEFT(CAL_ID,4)-1900)*12)+LEFT(RIGHT(CAL_ID,4),2)-1,RIGHT(CAL_ID,2)-1) from B_CALENDAR where CAL_DAY_PK = 263 and HDATE >= DateAdd(dd, DateDiff(dd,0,@StartDate), 0)
Insert Into @Holidays (HDate) Select HolidayDate from V_BUS_HOL Where HolidayDate >= DateAdd(dd, DateDiff(dd,0,@StartDate), 0)
If CAST(@StartDate as TIME) < @StartHour Set @StartDate = CAST(CAST(@StartDate as DATE) as DATETIME) + CAST(@StartHour as DATETIME) -- If Start time is less than start hour, set it to start hour
If CAST(@StartDate as TIME) >= DATEADD(HOUR,1,@EndHour) Set @StartDate = CAST(CAST(DATEADD(DAY,1,@StartDate) as DATE) as DATETIME) + CAST(@StartHour as DATETIME) -- If Start time is after end hour, set it to start hour of next day
If CAST(@EndDate as TIME) >= DATEADD(HOUR,1,@EndHour) Set @EndDate = CAST(CAST(@EndDate as DATE) as DATETIME) + CAST(@EndHour as DATETIME) -- If End time is after end hour, set it to end hour
If CAST(@EndDate as TIME) < @StartHour Set @EndDate = CAST(CAST(DATEADD(DAY,-1,@EndDate) as DATE) as DATETIME) + CAST(@EndHour as DATETIME) -- If End time is before start hour, set it to end hour of previous day
If @StartDate>@EndDate Return 0
-- If Start and End is on same day
If DateDiff(Day,@StartDate,@EndDate) <= 0
Begin
If Datepart(dw,@StartDate)>1 And DATEPART(dw,@StartDate)<7 -- If day is between sunday and saturday
If (Select Count(*) From @Holidays Where HDATE=DateAdd(dd, DateDiff(dd,0,@StartDate), 0)) = 0 -- If day is not a holiday
If @EndDate<@StartDate Return 0 Else Set @WorkMin=DATEDIFF(SECOND, @StartDate, @EndDate) -- Calculate difference
Else Return 0
Else Return 0
End
Else Begin
Declare @Partial int=1 -- Set partial day flag
While DateDiff(Day,@StartDate,@EndDate) > 0 -- While start and end days are different
Begin
If Datepart(dw,@StartDate)>1 And DATEPART(dw,@StartDate)<7 -- If this is a weekday
Begin
If (Select Count(*) From @Holidays Where HDATE=DateAdd(dd, DateDiff(dd,0,@StartDate), 0)) = 0 -- If this is not a holiday
Begin
If @Partial=1 -- If this is the first iteration, calculate partial time
Begin
Set @WorkMin=@WorkMin + DATEDIFF(SECOND, @StartDate, DateAdd(hour, DATEPART(HOUR,@EndHour), DateDiff(DAY, 0, @StartDate)))
Set @StartDate=DateAdd(hour, DATEPART(HOUR,@StartHour)+24, DateDiff(DAY, 0, @StartDate))
Set @Partial=0
End
Else Begin -- If this is a full day, add full minutes
Set @WorkMin=@WorkMin + (DATEPART(HOUR,@EndHour)-DATEPART(HOUR,@StartHour))*60
Set @StartDate = DATEADD(DD,1,@StartDate)
End
End
Else Set @StartDate = DATEADD(DD,1,@StartDate)
End
Else Set @StartDate = DATEADD(DD,1,@StartDate)
End
If Datepart(dw,@StartDate)>1 And DATEPART(dw,@StartDate)<7 -- If last day is a weekday
If (Select Count(*) From @Holidays Where HDATE=DateAdd(dd, DateDiff(dd,0,@StartDate), 0)) = 0 -- And it is not a holiday
If @Partial=0 Set @WorkMin=@WorkMin + DATEDIFF(SECOND, @StartDate, @EndDate) Else Set @WorkMin=@WorkMin + DATEDIFF(SECOND, DateAdd(hour, DATEPART(HOUR,@StartHour), DateDiff(DAY, 0, @StartDate)), @EndDate)
End
If @Reverse=1 Set @WorkMin=-@WorkMin
Return @WorkMin
End
【问题讨论】:
-
那么您想如何处理在
@BusinessDayStart之前开始和/或在@BusinessDayEnd之后结束的时间?只是截断/忽略这些边界之外存在的时间?听起来就是这样。 -
1 月 8 日:“我明天有一个可交付的业务”。然后沉默。
-
抱歉,Ross,我想出了一个对公式的修复,但在这一点上,我不记得实际的解决方案是什么,而且我不再像以前的工作那样访问查询.
标签: sql sql-server-2008 datetime business-intelligence