TTMSFNCGanttChart 1.3.3.10 — positive lag after a predecessor that ends right before a holiday is too short (GetActualEndDateTime)

Hello,

this one is urgent for us: we are about to ship the first release of a scheduling module built on TTMSFNCGanttChart (1.3.3.10, Delphi 13.1, VCL), and it produces start dates that are too early in a very common situation.

A finish-to-start link with a positive lag in work days gives a successor start that is one or more days too early when the predecessor ends right before a holiday. The holiday is counted as part of the lag.

Demo (attached, LagAfterNonWorkingTime.zip, VCL, Win32, no design-time components): the program runs by itself and logs, for three calendars and lags of 0 to 3 work days, the successor start, the expected start and the direct result of GetActualEndDateTime. In all scenarios WorkingHours are empty (day-based scheduling) and both tasks use whWorkDaysOnly. Result on our machine (also in the zip):

Scenario lag 1 lag 2 lag 3
1. Mon–Fri, holiday on Thu 2026-11-05, A ends Wed B starts Fri (expected Mon) ok ok
2. Mon–Fri, no holiday, A ends Fri ok ok ok
3. All seven days in WorkingDays, weekends as holidays, A ends Fri Mon (expected Tue) Mon (expected Wed) Tue (expected Thu)

Lag 0 is correct everywhere. Scenario 3 is how our application works (we need single working Saturdays, so weekends come as holidays). Scenario 1 shows that a plain Mon–Fri calendar is affected as well, as soon as a holiday follows the predecessor.

Cause (VCL.TMSFNCGanttClasses.pas): CalculateTaskTimes → GetDelayedTime(t.ScheduledEnd, ATaskDependency.Delay) (line 3058) → TTMSFNCGanttWorkTime.GetActualEndDateTime (line 6876), called with A.ScheduledEnd – the first moment after A, which here is the start of the holiday.

  • Without WorkingHours, IsInWorkingHours is True for any moment (line 6523). So the first window is [tempD, GetNextEnd(tempD)] (line 6894), although tempD lies in a holiday.
  • If that window already contains enough work time for the lag, the loop ends at once and the result is tempD + tl (line 6919) – counted from the start of the holiday, so the holiday days count as lag. Scenario 1, lag 1: Thursday 00:00 + 1 day = Friday. Scenario 3, lag 1: Saturday 00:00 + 1 day = Sunday, moved to Monday.
  • Only when the window is too short is tempD moved to a working start via GetActualStartDateTime. That is why lags 2 and 3 are right in scenario 1, and why the normal weekend in scenario 2 is right: there GetNextEnd returns Friday 23:59:59, which is before tempD.

Suggested fix: move the start to the next working time before the loop, for example at the beginning of the if (ADateTime > 0) and (AWorkTimePolicy <> whAllTime) branch:

tempD := GetActualStartDateTime(ADateTime, AWorkTimePolicy);

The demo checks this with public methods only (GetActualStartDateTime before GetActualEndDateTime, column "suggested fix"): all 12 results are then correct. A start that already is a working moment is not changed, so the end calculation of a task itself stays as it is.

We cannot work around it from the application: the lag is evaluated inside CalculateTaskTimes / GetPlannedStartForDependency, which are not virtual. A fix in the next update would help us a lot.

Thanks!

LagAfterNonWorkingTime.zip (7.4 KB)

Hello,

We've made the necessary changes for your request.
And we will try to have a build 1.3.3.12 for this by tomorrow.

Kind regards,

Thank you, Gjalt, that's great news! I'll test 1.3.3.12 with the demo from this thread as soon as it is available and report back here.

Thanks, Gjalt. I installed 1.3.3.13 and ran the demo from this thread again: 0 wrong results out of 12 (with 1.3.3.11 it was 4 out of 12). In our application a lag of 1, 2 and 3 work days after a task that ends on a Friday now gives Tuesday, Wednesday and Thursday (before: Monday, Monday, Tuesday), and our critical path calculation agrees with the new dates.

Because our code also relies on the backward calculation, I checked the changes in GetActualStartDateTimeByEnd as well: 120 round-trip cases (a holiday in mid-week, a working Saturday, overlapping company holidays, calendar days) and 70 cases of "n work days before a start date" give exactly the same results as with 1.3.3.10, and so do finish-to-finish links with a negative lag. No side effects for us. We have now also removed our own workaround for the backward work-day calculation, and the results stay the same.

Thank you for the fix!