Я протестировал все предложенные здесь решения, и ни одно из них не работает.Вот несколько тестовых сценариев, которые сломали множество вышеперечисленных решений.(при условии, что суббота и воскресенье - дни, которые вы исключаете):
-Добавить 0 дней к субботе - Ожидаемый результат = суббота
-Добавить 0 дней к воскресенью - Ожидаемый результат = воскресенье
-Добавить 1 день в пятницу - Ожидаемый результат = следующий понедельник
-Добавить 1 день в субботу - Ожидаемый результат = следующий понедельник
-Добавить 1 день в воскресенье -Ожидаемый результат = следующий понедельник
-Добавить 3 дня к пятнице - Ожидаемый результат = следующая среда
-Добавить 5 дней к субботе - Ожидаемый результат = следующая пятница
-Добавить 5 дней к пятнице - Ожидаемый результат = следующая пятница
-Вычитать 1 день из понедельника - Ожидаемый результат = предыдущая пятница
-Вычитать 1 день из воскресенья - Ожидаемый результат = предыдущаяПятница
- вычитать 1 день с субботы - ожидаемый результат = предыдущая пятница
- вычитать 3 дня с понедельника - ожидаемый результат = предыдущая среда
- вычитать 5 днейс субботы - ожидаемый результат = предыдущий понедельник
- вычесть 5 дней с понедельника - ожидаемый результат = предыдущий понедельник
Вот что я написал после прочтения всей этой цепочки и выбора хороших вещейлогики:
CREATE FUNCTION [dbo].[BusinessDateAdd]
(
@FromDate DATE
,@DaysToAdd INT
)
RETURNS DATE
AS
BEGIN
--If there are no days to add or subtract, return the day that was passed in
IF @DaysToAdd = 0 RETURN @FromDate
DECLARE @Weeks INT
DECLARE @DMod INT
DECLARE @FromDateIndex INT
--number of weeks
SET @Weeks = @DaysToAdd/5
--remainder of days
SET @dmod = @DaysToAdd%5
--Get the FromDate day of the week, this logic standardizes the @@DateFirst to Sunday = 1
SET @FromDateIndex = (DATEPART(weekday, @FromDate) + @@DATEFIRST - 1) % 7 + 1
/*Splitting the addition vs subtraction logic for readability*/
--Adding business days
IF @DaysToAdd > 0
BEGIN
--If the FromDate is on a weekend, move it to the previous Friday
IF @FromDateIndex IN(1,7)
BEGIN
SET @FromDate = DATEADD(dd,CASE @FromDateIndex WHEN 1 THEN -2 WHEN 7 THEN -1 END,@FromDate)
SET @FromDateIndex = 6
END
SET @FromDate = DATEADD(dd,
CASE
--If the mod goes through the weekend, add 2 days to account for it
WHEN
((@FromDateIndex = 3 --Tuesday
AND @dmod > 3) --Days until Friday
OR
(@FromDateIndex = 4 --Wednesday
AND @dmod > 2)--Days until Friday
OR
(@FromDateIndex = 5 --Thursday
AND @dmod > 1)--Days until Friday
OR
(@FromDateIndex = 6 --Friday
AND @dmod > 0))--Days until Friday
THEN
@DMod+2
--Otherwise just add the mod
ELSE
@DMod
END, @FromDate)
END
--Subtracting business days
IF @DaysToAdd < 0
BEGIN
--If the FromDate is on a weekend, move it to the next Monday
IF @FromDateIndex IN(1,7)
BEGIN
SET @FromDate = DATEADD(dd,CASE @FromDateIndex WHEN 1 THEN 1 WHEN 7 THEN 2 END,@FromDate)
SET @FromDateIndex = 2
END
SET @FromDate = DATEADD(dd,
CASE
--If the mod goes through the weekend, subtract 2 days to account for it
WHEN
((@FromDateIndex = 5 --Thursday
AND @dmod < -3) --Days until Monday
OR
(@FromDateIndex = 4 --Wednesday
AND @dmod < -2)--Days until Monday
OR
(@FromDateIndex = 3 --Tuesday
AND @dmod < -1)--Days until Monday
OR
(@FromDateIndex = 2 --Monday
AND @dmod < 0))--Days until Monday
THEN
@DMod-2
--Otherwise just subtract the mod
ELSE
@DMod
END, @FromDate)
END
--Shift the date by the number of weeks
SET @FromDate = DATEADD(ww,@Weeks,@FromDate)
RETURN @FromDate
END