Termin to 3 dzień roboczy od daty dodania akcji

0

Dobry wieczór.
Mam taska gdzie muszę znaleźć trzeci dzień roboczy od daty utworzenia akcji. Dzień utworzenia akcji jest DNIEM ZEROWYM.
Jedyne co udało mi się wymyślić to:
1)

Case
when DATEPART(weekday,GETDATE())=1
then dateadd(dd,3,a.DataDodania)
when DATEPART(weekday,GETDATE())=2
then dateadd(dd,4,a.DataDodania)
when DATEPART(weekday,GETDATE())=3
then dateadd(dd,4,a.DataDodania)
when DATEPART(weekday,GETDATE())=4
then dateadd(dd,5,a.DataDodania)
when DATEPART(weekday,GETDATE())=5
then dateadd(dd,6,a.DataDodania)
when DATEPART(weekday,GETDATE())=6
then dateadd(dd,5,a.DataDodania)
else
dateadd(dd,4,a.DataDodania)
end [termin]
*a.DataDodania+[WorkingDays] (a.DataDodania,a.dataDodania+3)*****

Niestety ale oba moje wymysły nie działają prawidłowo. Poniżej dołączam skrypt "ogólnodostępnych funkcji" które wykorzystuję. [WorkingDays] i [GetHolidays]

ALTER function [GetHolidays](@year int)

returns @Dates table (HolidayDate date, HolidayName nvarchar(100))

as begin

 declare @Easter date

 set @Easter = [GetEaster](@year)

insert into @Dates values

(DATEFROMPARTS(@year, 1, 1), 'Nowy Rok'),

(DATEFROMPARTS(@year, 1, 6), 'Trzech Króli (Objawienie Pańskie)'),

(@Easter, 'Wielkanoc'),

(dateadd(day, 1, @Easter), 'Poniedziałek Wielkanocny'),

(DATEFROMPARTS(@year, 5, 1), 'Międzynarodowe Święto Pracy'),

(DATEFROMPARTS(@year, 5, 3), 'Święto Konstytucji 3 Maja'),

(dateadd(day, 60, @Easter), 'Boże Ciało'),

(DATEFROMPARTS(@year, 8, 15), 'Święto Wojska Polskiego, Wniebowzięcie Najświętszej Maryi Panny'),

(DATEFROMPARTS(@year, 11, 1), 'Wszystkich Świętych'),

(DATEFROMPARTS(@year, 11, 11), 'Narodowe święto Niepodległości'),

(DATEFROMPARTS(@year, 12, 25), 'Boże Narodzenie (pierwszy dzień)'),

(DATEFROMPARTS(@year, 12, 26), 'Boże Narodzenie (drugi dzień)')

return

end
--------------------------

ALTER FUNCTION [WorkingDays] ( @StartDate datetime, @EndDate datetime)

RETURNS int

AS BEGIN

DECLARE @days int 

DECLARE @SatName nvarchar(100),@SunName nvarchar(100) 

SELECT @SatName = DATENAME(dw,5), @SunName = DATENAME(dw,6) 

SELECT @days = (DATEDIFF(d,@StartDate ,@EndDate )+1) - DATEDIFF(wk,@StartDate ,@EndDate ) * 2 

-(CASE WHEN DATENAME(dw, @StartDate) =  @SunName THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, @EndDate) =  @SatName THEN 1 ELSE 0 END) 


- (SELECT COUNT(*) FROM GetHolidays(year(@StartDate))

WHERE HolidayDate BETWEEN @StartDate AND @EndDate  AND DATENAME(dw, HolidayDate) <> @SatName 

AND DATENAME(dw, HolidayDate) <> @SunName) RETURN (@days)

ObrazekNa4Programmers.png

2

A pytanie brzmi?

0

@vpiotr: W jaki sposób mogę poprawić pierwsze lub drugie moje rozwiązanie 1) , 2) , aby zapytanie z obrazka dało mi w kolumnie termin 1 albo termin 2 poprawną datę, którą jest 3 dzień roboczy od daty dodania akcji, gdzie dzień w którym akcja została dodana jest dniem zerowym?

1

Podstawowe pytanie - czy to ma również uwzględniać święta ruchome i nieruchome? Dla jakich państw / regionów / religii / tylko ustawowo wolne od pracy czy dodatkowe też?

Jeśli masz do ogranięcia takie rzeczy to ifologią raczej tego nie załatwisz (chyba, że będziesz dodawać sobie nową ifologię na rok w przód i tak co roku), tym bardziej nie załatwisz tego na samych weekdayach.

3

Generalnie, ja do takich rzeczy tworzę tabelę, coś w tym kierunku:

create table FreeDays (y int, m int, d int, HolidayName nvarchar(100))


insert into FreeDays values
(null, 1, 1, 'Nowy Rok'),
(null, 1, 6, 'Trzech Króli (Objawienie Pańskie)'),
(2021,4,4, 'Wielkanoc'),
(2021,4,5, 'Poniedziałek Wielkanocny'),
(null, 5, 1, 'Międzynarodowe Święto Pracy'),
(null, 5, 3, 'Święto Konstytucji 3 Maja'),
(null, 8, 15, 'Święto Wojska Polskiego, Wniebowzięcie Najświętszej Maryi Panny'),
(null, 11, 1, 'Wszystkich Świętych'),
(null, 11, 11, 'Narodowe święto Niepodległości'),
(null, 12, 25, 'Boże Narodzenie (pierwszy dzień)'),
(null, 12, 26, 'Boże Narodzenie (drugi dzień)')

Jeżeli świeto jest stałe to w y mam null, jeżeli dla danego roku to jest tam literanie rok.

Teraż jedyne co trzeba zrobić to sprawdzić czy data od której liczę w kolejnych dniach nie ma świąt niedziel i je pominąc, można napisac prostą funkcję:


CREATE  FUNCTION [dbo].[termin]
				(@dt datetime,
			 	 @il int)
RETURNS datetime
AS
BEGIN

DECLARE @Wynik datetime
--wszystkie dni od przekazanej dady
;with daysall as (
select
	dateadd(d,number,@dt) dt
from 
    master..spt_values 
where 
    type = 'p' 
    and number between 0 and 10
), 
--tabela ze swiętami
fdays as (
select 
	DATEFROMPARTS(isnull(y,year(@dt)), m, d) fd 
from 
	FreeDays
)
--tylko "pracujące dni
, workingdays as (
select 
	*
from 
	daysall 
	left join fdays on fdays.fd=daysall.dt 
where
	case when DATEPART(weekday,dt) = 7 or not fd is null then 1 else 0 end = 0
	and dt>@dt
)

--wynik
select @wynik = dt from (
select row_number() over (order by dt) r, dt from workingdays) dt where r = @il

RETURN @Wynik
END


GO

Tutaj jest WAŻNE aby korzystając z takiej funkcji użyc prawidłowo SET DATEFIRST lub przerobić funkcję aby zwracała na to uwagę:


set datefirst 1
select dbo.termin('2020-12-31',3)

1 użytkowników online, w tym zalogowanych: 0, gości: 1