Calculate business hours between two dates

前端 未结 14 1127
被撕碎了的回忆
被撕碎了的回忆 2020-11-27 05:06

How can I calculate business hours between two dates? For example we have two dates; 01/01/2010 15:00 and 04/01/2010 12:00 And we have working hours 09:00 to 17:00 in weekda

相关标签:
14条回答
  • 2020-11-27 05:43

    An alternative solution from @Pavanred's, coming at things from a more data-based angle:

    Create a table with all the dates you want to consider in it. For each day, set a number of working hours, like so:

    WorkingDate Hours Comment
    =========== ===== ==================
     1 Jan 2011     0 Saturday
     2 Jan 2011     0 Sunday
     3 Jan 2011     0 Public Holiday
     4 Jan 2011     8 Normal working day
     5 Jan 2011     8 Normal working day
    
     -- and so on, for all the days you want to report on.
    

    This will take a small amount of setting up -- you can pre-populate it for weeks versus weekends automatically, then adjust for public holidays, etc, as necessary.

    But, what you lose in the setting up, you gain in ease of querying:

    SELECT
      SUM(Hours) 
    FROM
      working_days 
    WHERE
      WorkingDate BETWEEN @StartDate AND @EndDate
    

    ...and this can work out as an easier approach if you need to start adding more complicated rules for what defines a working day, or if your working hours vary depending on the day, etc.

    It also makes the rules more easily "editable", as you don't need to change any actual code to change the definitions of a working day, add public holidays, etc.

    0 讨论(0)
  • 2020-11-27 05:51

    A version I wrote today taking into account bank holidays. Note: This is not thoroughly tested and could no doubt be improved.

    CREATE FUNCTION [dbo].[WorkingHoursBetween2Dates]
    (
        @dtFrom datetime,
        @dtTo datetime
    )
    RETURNS INT
    BEGIN
        DECLARE @tblDates AS TABLE (DateValue DATE)
        DECLARE @dFrom date = @dtFrom
        DECLARE @dTo date = @dtTo
        DECLARE @intDays int
        DECLARE @intHours int = 0
        DECLARE @dFromWorkday bit = CASE WHEN (DATENAME(WEEKDAY, @dFrom) IN ('Saturday','Sunday')) OR EXISTS (SELECT * FROM dbo.BankHolidays WHERE BankHolidayDate = @dFrom) THEN 0 ELSE 1 END
        DECLARE @dToWorkday bit = CASE WHEN (DATENAME(WEEKDAY, @dTo) IN ('Saturday','Sunday')) OR EXISTS (SELECT * FROM dbo.BankHolidays WHERE BankHolidayDate = @dTo) THEN 0 ELSE 1 END
    
    
    
        IF DATEPART(HOUR,@dtFrom) < 9
            SET @dtFrom = DATEADD(HOUR,9,CAST(CAST(@dtFrom AS DATE) AS DATETIME))
        ELSE
            IF DATEPART(HOUR,@dtFrom) > 17
                SET @dtFrom = DATEADD(HOUR,17,CAST(CAST(@dtFrom AS DATE) AS DATETIME))
    
        IF DATEPART(HOUR,@dtTo) < 9
            SET @dtTo = DATEADD(HOUR,9,CAST(CAST(@dtTo AS DATE) AS DATETIME))
        ELSE
            IF DATEPART(HOUR,@dtTo) > 17
                SET @dtTo = DATEADD(HOUR,17,CAST(CAST(@dtTo AS DATE) AS DATETIME))
    
    
    
        WHILE @dFrom <= @dTo
        BEGIN
            INSERT INTO @tblDates
            (
                DateValue
            )
                SELECT @dFrom
                WHERE NOT ((DATENAME(WEEKDAY, @dFrom) IN ('Saturday','Sunday')) OR EXISTS (SELECT * FROM dbo.BankHolidays WHERE BankHolidayDate = @dFrom))
            
            SET @dFrom = DATEADD(DAY,1,@dFrom)
        END
        
        SET @intDays = CASE WHEN EXISTS(SELECT * FROM @tblDates) THEN (SELECT COUNT(*) FROM @tblDates) - 1 ELSE 0 END
    
        IF @intDays = 0
            BEGIN
                IF @dFromWorkday = 1
                    IF DATEPART(HOUR,@dtFrom) < 17
                        BEGIN
                            IF DATEDIFF(DAY,@dtFrom,@dtTo)=0
                                SET @intHours = DATEDIFF(HOUR,@dtFrom,@dtTo)
                            ELSE
                                SET @intHours = DATEDIFF(HOUR,@dtFrom,DATEADD(HOUR,17,CAST(CAST(@dtFrom AS DATE) AS DATETIME)))
                        END
    
                IF @dToWorkday = 1 AND DATEDIFF(DAY,@dtFrom,@dtTo)<>0
                    IF DATEPART(HOUR,@dtTo) >= 17
                        SET @intHours = @intHours + 8
                    ELSE
                        IF DATEPART(HOUR,@dtTo) > 9
                            SET @intHours = @intHours + DATEPART(HOUR,@dtTo) - 9
            END
        ELSE
            BEGIN
                IF @dFromWorkday = 1
                    IF DATEPART(HOUR,@dtFrom) < 17
                        BEGIN
                            SET @intHours = DATEDIFF(HOUR,@dtFrom,DATEADD(HOUR,17,CAST(CAST(@dtFrom AS DATE) AS DATETIME)))
                            SET @intDays = @intDays - 1
                        END
    
                IF DATEPART(HOUR,@dtTo) < 17
                    SET @intHours = @intHours + (@intDays * 8) + CASE WHEN @dToWorkday = 1 THEN DATEDIFF(HOUR,DATEADD(HOUR,9,CAST(CAST(@dtTo AS DATE) AS DATETIME)), @dtTo) ELSE 0 END
                ELSE
                    SET @intHours = @intHours + ((@intDays + 1) * 8)
            END
    
        RETURN (@intHours)
    END
    
    0 讨论(0)
提交回复
热议问题