【问题标题】:Calculate seconds between two dates including business hours, excluding holidays, start hour 08:30计算两个日期之间的秒数,包括营业时间,不包括节假日,开始时间 08:30
【发布时间】:2019-05-11 05:30:56
【问题描述】:

在为我的问题寻找解决方案时,我发现了以下 sql (Calculate business hours between two dates)。

但是,我希望起点是 8:30 而不是 9,终点是 17:30 而不是 17。目前我使用的是整数。谁能帮我这个?提前致谢!

    Create Function GetWorkingMin(@StartDate DateTime, @EndDate DateTime, @Country Varchar(2)) Returns Int 
AS
Begin
Declare @WorkMin int = 0   -- Initialize counter
Declare @Reverse bit       -- Flag to hold if direction is reverse
Declare @StartHour int = 9   -- Start of business hours (can be supplied as an argument if needed)
Declare @EndHour int = 17    -- 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 HDate from HOLIDAY Where COUNTRYCODE=@Country and HDATE>=DateAdd(dd, DateDiff(dd,0,@StartDate), 0)

If DatePart(HH, @StartDate)<@StartHour Set @StartDate = DateAdd(hour, @StartHour, DateDiff(DAY, 0, @StartDate))  -- If Start time is less than start hour, set it to start hour
If DatePart(HH, @StartDate)>=@EndHour+1 Set @StartDate = DateAdd(hour, @StartHour+24, DateDiff(DAY, 0, @StartDate)) -- If Start time is after end hour, set it to start hour of next day
If DatePart(HH, @EndDate)>=@EndHour+1 Set @EndDate = DateAdd(hour, @EndHour, DateDiff(DAY, 0, @EndDate)) -- If End time is after end hour, set it to end hour
If DatePart(HH, @EndDate)<@StartHour Set @EndDate = DateAdd(hour, @EndHour-24, DateDiff(DAY, 0, @EndDate)) -- 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(MI, @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(MI, @StartDate, DateAdd(hour, @EndHour, DateDiff(DAY, 0, @StartDate)))
                    Set @StartDate=DateAdd(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 + (@EndHour-@StartHour)*60        
                    Set @StartDate = DATEADD(DD,1,@StartDate)
                End
            End
            Else Set (at)StartDate = DATEADD(HOUR, (at)StartHour, CAST(CAST(DATEADD(DD,1,(at)StartDate) AS DATE) AS DATETIME))  
        End
        Else Set (at)StartDate = DATEADD(HOUR, (at)StartHour, CAST(CAST(DATEADD(DD,1,(at)StartDate) AS DATE) AS DATETIME))
    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(MI, @StartDate, @EndDate) Else Set @WorkMin=@WorkMin + DATEDIFF(MI, DateAdd(hour, @StartHour, DateDiff(DAY, 0, @StartDate)), @EndDate)
End 
If @Reverse=1 Set @WorkMin=-@WorkMin
Return @WorkMin

结束

【问题讨论】:

  • 为什么@StartHour 不使用 TIME 而不是 INT?
  • 我们尝试用时间而不是整数重写整个 sql,但输出不再匹配。困难的是在所有计算中都使用分钟。例如:如果开始时间小于开始小时,则将其设置为开始小时。
  • 我已经为您提供了示例答案。我相信您可以通过这种方式改进您的功能。

标签: sql sql-server-2008 datetime


【解决方案1】:

使用TIME 作为开始时间。然后创建INT 变量,将转换后的值转换为分钟以用于条件。

我已经为你创建了示例。

DECLARE @StartDate  DATETIME='2018-12-10 10:00'
DECLARE @ExpectedStartTime  TIME='08:30'

DECLARE @ExpectedStartMin   INT=DATEPART(HOUR,@ExpectedStartTime)*60+DATEPART(MINUTE,@ExpectedStartTime)
DECLARE @ActualStartMin     INT=DATEPART(HOUR,@StartDate)*60+DATEPART(MINUTE,@StartDate)

--Check before change the StartDate
SELECT @ExpectedStartMin, @ActualStartMin, @StartDate


If @ExpectedStartMin<@ActualStartMin Set @StartDate = CAST(CAST(@StartDate AS DATE) AS DATETIME)+@ExpectedStartTime
-- same way to the other conditions.
--
--

--Check after change the StartDate  
SELECT @ExpectedStartMin, @ActualStartMin, @StartDate

【讨论】:

    猜你喜欢
    • 2023-03-26
    • 1970-01-01
    • 2018-04-04
    • 2019-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-08
    • 1970-01-01
    相关资源
    最近更新 更多