Calculate date without counting weekends and holidays

I need to calculate future dates through a number of days, but one should not count the end of weeks and holidays.

Look at the example: the project starts on 01/01/2020 and lasts 25 days, that is, it has to end on 29/01/2020 (skipping the weekends and the holiday of January 1).

I made a if with IncDay but it only made skip the first weekend, that is, I have no idea where to start to solve that problem.

Follows the code I've done so far:

    procedure TformPrincipal.QueryProjItemCalcFields(DataSet: TDataSet);
var
    dtFim: TDateTime;
    dtSemFds: TDateTime;
begin

    //zerar os campos se a duração tiver vazia
    if QueryProjItemprojitem_duracao.Value=0
    then
        begin
            QueryProjItemvlcustorecurso.AsFloat:=0;
        end
    else
        begin
            //Calcula a data de acordo com a duração sem FDS
            dtFim:=(QueryProjItemprojitem_dt_inicio.AsDateTime + QueryProjItemprojitem_duracao.AsInteger);

            if DayOfWeek(dtFim)=1 then
                    dtFim:= incDay(dtFim,1)
                else
                if DayOfWeek(dtFim)=7 then
                    dtFim:= incDay(dtFim,2);

            QueryProjItemdtFinal.AsDateTime :=dtFim;


            //Calcula o valor total dos recursos de acordo com a duração
            QueryProjItemvlcustorecurso.AsFloat:=
            QueryProjItemrec_vl.AsFloat * QueryProjItemprojitem_duracao.AsInteger;


        end;

end;
Author: David, 2019-06-19

1 answers

Following @hkotsubo's tip, I developed the following code that solved my problem:

procedure TformPrincipal.QueryProjItemCalcFields(DataSet: TDataSet);
var
dtFim: TDateTime;
duracao: Integer;
begin
//zerar os campos se a duração tiver vazia
if QueryProjItemprojitem_duracao.Value=0
then
    begin
        QueryProjItemvlcustorecurso.AsFloat:=0;
    end
else
    begin
        dtFim:=QueryProjItemprojitem_dt_inicio.AsDateTime;
        duracao:=2;
        while duracao <= QueryProjItemprojitem_duracao.AsInteger do
        begin
               dtFim:= IncDay(dtFim,1);
                while (DayOfWeek(dtFim)=1) or (DayOfWeek(dtFim)=7) do
                begin
                    if DayOfWeek(dtFim)=1 then
                        dtFim:= IncDay(dtFim,1);
                    if DayOfWeek(dtFim)=7 then
                        dtFim:=IncDay(dtFim,2);
                end;
             duracao:=duracao + 1;
        end;
        QueryProjItemdtFinal.AsDateTime :=dtFim;

        //Calcula o valor total dos recursos de acordo com a duração
        QueryProjItemvlcustorecurso.AsFloat:=
        QueryProjItemrec_vl.AsFloat * 
        QueryProjItemprojitem_duracao.AsInteger;


    end;

end;
 0
Author: Felipe Neiva, 2019-06-19 15:34:38