Add business days to date in SQL without loops

后端 未结 25 2945
无人共我
无人共我 2020-12-02 22:54

I currently have a function in my SQL database that adds a certain amount of business days to a date, e.g. if you enter a date that is a Thursday and add two days, it will r

25条回答
  •  暗喜
    暗喜 (楼主)
    2020-12-02 23:22

    --Refactoring my original answer... I've added the option to define the starting point of the calculation if the starting date happens to be a weekend day: start from that weekend day or shift to the nearest weekday depending on the direction of the delta.

    DECLARE
        @input DATE = '2019-06-15', -- if null, then returns null
        @delta INT = 1, -- can be positive or negative; null => zero
        @startFromWeekend BIT = 1 -- null => zero
    
    -- input is null, delta is zero/null
    IF @input IS NULL OR ISNULL(@delta, 0) = 0
        SELECT @input
    
    -- input is not null and has delta
    ELSE
    BEGIN
        DECLARE
            @input_dw INT = (DATEPART(DW, @input) + @@DATEFIRST - 1) % 7, -- input day of week
            @weeks    INT = @delta / 5, -- adjust by weeks
            @days     INT = @delta % 5  -- adjust by days
    
        -- if input is a weekend day, offset it for proper calculation
        -- !!important!!: depends on *your* definition of the starting date to perform calculation from
        DECLARE @offset INT =
            -- start calc from weekend day that is nearest to a weekday depending on delta direction
            -- pos delta: effectively Sunday of the weekend   (actual: prev Friday)
            -- neg delta: effectively Saturday of the weekend (actual: next Monday)
            CASE WHEN ISNULL(@startFromWeekend, 0) = 1
            THEN CASE WHEN @delta > 0
                THEN CASE @input_dw
                    WHEN 0 THEN -2
                    WHEN 6 THEN -1
                    END
                ELSE CASE @input_dw
                    WHEN 0 THEN  1
                    WHEN 6 THEN  2
                    END
                END
            -- start calc from nearest weekday depending on delta direction
            -- pos delta: next Monday from the weekend
            -- neg delta: prev Friday from the weekend
            ELSE CASE WHEN @delta > 0
                THEN CASE @input_dw
                    WHEN 0 THEN  1
                    WHEN 6 THEN  2
                    END
                ELSE CASE @input_dw
                    WHEN 0 THEN -2
                    WHEN 6 THEN -1
                    END
                END
            END
    
        -- calculate: add weeks, add days, add initial correction offset
        DECLARE @output DATE = DATEADD(DAY, @days + ISNULL(@offset, 0), DATEADD(WEEK, @weeks, @input))
    
        -- finally, if output is weekend, add final correction offset depending on delta direction
        SELECT
            CASE WHEN (DATEPART(DW, @output) + @@DATEFIRST - 1) % 7 IN (0,6)
            THEN CASE 
                WHEN @delta > 0 THEN DATEADD(DAY,  2, @output)
                WHEN @delta < 0 THEN DATEADD(DAY, -2, @output)
                END
            ELSE @output
            END
    END
    

提交回复
热议问题