josh-jw Ответов: 3

исключите субботу и воскресенье из расчета дат


я хочу исключить субботу и воскресенье при расчете даты.например, если мой период даты равен 5 и вычисляется с сегодняшнего дня , мне нужен результирующий день как 12/26/2012.

charlie literato

пожалуйста, помогите мне, я хотел бы исключить праздники для отображения с помощью sql-запросов, у меня есть отдельная таблица для списка праздников и дата пришла из табличных функций

3 Ответов

Рейтинг:
12

__TR__

Попробуй

DECLARE @Date DATETIME
SET @Date = GETDATE()

DECLARE @DaysToAdd INT
SET @DaysToAdd = 5

DECLARE @DayOfWeek INT

SELECT @DayOfWeek = CASE WHEN DATENAME(w,@Date) = 'Sunday' THEN 1
			WHEN DATENAME(w,@Date) = 'Monday' THEN 2
			WHEN DATENAME(w,@Date) = 'Tuesday' THEN 3
			WHEN DATENAME(w,@Date) = 'Wednesday' THEN 4
			WHEN DATENAME(w,@Date) = 'Thursday' THEN 5
			WHEN DATENAME(w,@Date) = 'Friday' THEN 6
			WHEN DATENAME(w,@Date) = 'Saturday' THEN 7 END 

IF @DaysToAdd + @DayOfWeek < 7
BEGIN

	SELECT CONVERT(VARCHAR,DATEADD(DAY,@DaysToAdd, @Date),101)

END
ELSE
BEGIN

	SELECT CONVERT(VARCHAR,DATEADD(DAY,@DaysToAdd+2, @Date),101)

END


[Редактировать]
Приведенный выше пример даст неверный результат, если количество добавляемых дней будет больше 7. Поэтому я придумал другой подход.
DECLARE @Date DATETIME
SET @Date = GETDATE() 
DECLARE @DaysToAdd INT
SET @DaysToAdd = 5



DECLARE @Count INT

DECLARE @TotalWeekEnds INT
SET @TotalWeekEnds = 0

DECLARE @Phase INT
SET @Phase = 0


CREATE TABLE #Dates 
(
	Phase INT,
	Date DateTime
)

;WITH CTE(n,Date) AS
(
	SELECT 0 AS n, @Date AS Date
	UNION ALL
	SELECT n+1 AS n, DATEADD(d,n+1, @Date) AS Date
	FROM CTE
	WHERE n < @DaysToAdd
)



INSERT INTO #Dates
SELECT 1, Date FROM CTE


SELECT @TotalWeekEnds = COUNT(*) FROM #Dates 
WHERE (DATENAME(w,Date) = 'Sunday' OR DATENAME(w,Date) = 'Saturday')

WHILE @TotalWeekEnds != 0
BEGIN
	SET @Count = 0
	SELECT @Phase = MAX(Phase) + 1 FROM #Dates
	WHILE @Count < @TotalWeekEnds
	BEGIN
		
		INSERT INTO #Dates
		SELECT @Phase, DATEADD(d,1,MAX(Date)) FROM #Dates

		SET @Count = @Count + 1
	END

	SELECT @TotalWeekEnds = COUNT(*) FROM #Dates 
	WHERE (DATENAME(w,Date) = 'Sunday' OR DATENAME(w,Date) = 'Saturday') AND Phase = @Phase

END


--SELECT * FROM #Dates

SELECT CONVERT(VARCHAR(10),MAX(Date),101) FROM #Dates

DROP TABLE #Dates

[/Редактировать]


Рейтинг:
0

Sohail Arshed

This is an old post but it might help someone. This query returns the exact days, months and hours between two dates excluded All Sunday(s) and Monday(s):
```
declare @d1 datetime, @d2 datetime
select @d1 = '11/25/2019 12:00:00',  @d2 = '12/02/2019 12:00:00'

SELECT  (DATEDIFF(MINUTE, @d1, @d2) -  DATEDIFF(WK, @d1, @d2) * 2880) + CASE WHEN  DATEDIFF(WK, @d1, @d2) = 1 AND DATEDIFF(DW, @d1, @d2) <= 5 THEN 0 ELSE 1440 END

SELECT (DATEDIFF(HOUR, @d1, @d2) - DATEDIFF(WK, @d1, @d2) * 48) + CASE WHEN  DATEDIFF(WK, @d1, @d2) = 1 AND DATEDIFF(DW, @d1, @d2) <= 5 THEN 0  ELSE 24 END

SELECT (DATEDIFF(DW, @d1, @d2) - DATEDIFF(WK, @d1, @d2) * 2) + CASE WHEN  DATEDIFF(WK, @d1, @d2) = 1 AND DATEDIFF(DW, @d1, @d2) <= 5 THEN 0  ELSE 1 END
```

Or you can use this generic function:

```
CREATE FUNCTION [dbo].[fn_GetBusinnessDaysTimeSpan]( 
 @DateFrom DATETIME,
 @DateTO DATETIME,
 @Type VARCHAR(50)
) 
RETURNS BIGINT
AS 
BEGIN 
		DECLARE @result AS BIGINT;
		IF @Type = 'Min'
		BEGIN
			SET @result = (SELECT  (DATEDIFF(MINUTE, @DateFrom, @DateTO) -  DATEDIFF(WK, @DateFrom, @DateTO) * 2880) + CASE WHEN  DATEDIFF(WK, @DateFrom, @DateTO) = 1 AND (DATEDIFF(DW, @DateFrom, @DateTO)) <= 5 THEN 0 ELSE 1440 END)
		END

		IF @Type = 'Hour'
		BEGIN
			SET @result = (SELECT (DATEDIFF(HOUR, @DateFrom, @DateTO) - DATEDIFF(WK, @DateFrom, @DateTO) * 48) + CASE WHEN  DATEDIFF(WK, @DateFrom, @DateTO) = 1 AND (DATEDIFF(DW, @DateFrom, @DateTO)) <=5 THEN 0  ELSE 24 END)
		END

		IF @Type = 'Day'
		BEGIN
			SET @result = (SELECT (DATEDIFF(DW, @DateFrom, @DateTO) - DATEDIFF(WK, @DateFrom, @DateTO) * 2) + CASE WHEN  DATEDIFF(WK, @DateFrom, @DateTO) = 1 AND (DATEDIFF(DW, @DateFrom, @DateTO)) <=5 THEN 0  ELSE 1 END)
        END
		RETURN @result 
END
```