I live in a country, where by law, certain holidays are not allowed to fall on a weekend. If they do, they need to be delayed to fall on the first available working day.
For example, the holiday of Saint-X always falls on the 19th day of April. If that day is a Saturday or Sunday, this holiday needs to be celebrated on the first free working day (not necessarily Monday - especially when Monday already hosts a different holiday). There were cases in the past when such a weekend-ish holiday needed to be postponed by 6 or even 9 days.
I'm having a hard time coming up with a formula to implement this simple rule. In my spreadsheet, I have a column A with regular holidays and column B with holidays that are required to be postponed.
Column C contains dates of days, and column D (expected output) should fix column C's special holidays.
[enter image description here]1
normal holidays | special holidays | A & B dates | fix (expected output) | ||
---|---|---|---|---|---|
26/9/2025 | 4/10/2025 | 26/9/2025 | 26/9/2025 | << C3 is holiday but Friday so the date will be copied | |
10/11/2025 | 18/10/2025 | 4/10/2025 | 6/10/2025 | << 4th is Saturday so +2 because 6th is first working day | |
12/11/2025 | 19/10/2025 | 18/10/2025 | 21/10/2025 | << +3 | |
13/11/2025 | 20/10/2025 | 19/10/2025 | 22/10/2025 | << +3 | |
17/11/2025 | 8/11/2025 | 20/10/2025 | 20/10/2025 | << copied over | |
1/1/2029 | 9/11/2025 | 8/11/2025 | 14/11/2025 | << +6 | |
7/1/2029 | 11/11/2025 | 9/11/2025 | 18/11/2025 | << +9 | |
8/1/2029 | 7/12/2025 | 10/11/2025 | 10/11/2025 | << copied over | |
9/1/2029 | 31/12/2028 | 11/11/2025 | 11/11/2025 | << copied over | |
6/1/2029 | 12/11/2025 | 12/11/2025 | << copied over | ||
10/1/2029 | 13/11/2025 | 13/11/2025 | << copied over | ||
17/11/2025 | 17/11/2025 | << copied over | |||
7/12/2025 | 8/12/2025 | << +1 | |||
31/12/2028 | 2/1/2029 | << +2 | |||
1/1/2029 | 1/1/2029 | << copied over | |||
6/1/2029 | 11/1/2029 | << +5 | |||
7/1/2029 | 7/1/2029 | << copied over | |||
8/1/2029 | 8/1/2029 | << copied over | |||
9/1/2029 | 9/1/2029 | << copied over | |||
10/1/2029 | 10/1/2029 | << copied over |
So far I got this far, but it is a nasty draggable formula with INDIRECTing that is not so ideal:
=IF(COUNTIF($B$3:$B$100, C3)=0, C3,
WORKDAY.INTL(C3-1, 1, "0000011",
FILTER({$A$3:$A$100; $B$3:$B$100; INDIRECT("D$3:D"&ROW()-1)},
({$A$3:$A$100; $B$3:$B$100; INDIRECT("D$3:D"&ROW()-1)} <> C3 )
*LEN({$A$3:$A$100; $B$3:$B$100; INDIRECT("D$3:D"&ROW()-1)}))))
Converting it to LAMBDA:
=BYROW(C3:C30, LAMBDA(x, LET(a, A3:A30, b, B3:B30,
d, INDIRECT(ADDRESS(3, COLUMN())&":"&ADDRESS(ROW(x)-1, COLUMN())),
IF(COUNTIF(b, x)=0, x, WORKDAY.INTL(x-1, 1, "0000011",
FILTER({a; b; d}, ({a; b; d}<>x)*LEN({a; b; d})))))))
With this I'm still failing to implement circular_reference-free recursion via LAMBDA. Hope someone can help.
You may try:
=LET(a, TOCOL(A2:A, 1),
b, TOCOL(B2:B, 1),
c, TOCOL(C2:C, 1),
d, FILTER(c, MATCH(c, a, 0)),
e, BYROW(b, LAMBDA(x, IF(WEEKDAY(x, 2) > 5, WORKDAY(x, 1, c), x))),
f, VSTACK(d, e),
SORT(SCAN("", f, LAMBDA(x, y, IF(COUNTIF(f, y) > 1, IF(x = y, WORKDAY(y, 1, c), y), y)))))
This outputs a sorted version of your expected results and works with Iterative calculation turned off.
D (sorted) | E |
---|---|
9/26/2025 | 9/26/2025 |
10/6/2025 | 10/6/2025 |
10/20/2025 | 10/20/2025 |
10/21/2025 | 10/21/2025 |
10/22/2025 | 10/22/2025 |
11/10/2025 | 11/10/2025 |
11/11/2025 | 11/11/2025 |
11/12/2025 | 11/12/2025 |
11/13/2025 | 11/13/2025 |
11/14/2025 | 11/14/2025 |
11/17/2025 | 11/17/2025 |
11/18/2025 | 11/18/2025 |
12/8/2025 | 12/8/2025 |
1/1/2029 | 1/1/2029 |
1/2/2029 | 1/2/2029 |
1/7/2029 | 1/7/2029 |
1/8/2029 | 1/8/2029 |
1/9/2029 | 1/9/2029 |
1/10/2029 | 1/10/2029 |
1/11/2029 | 1/11/2029 |
If the mapping of dates is important for future use, you may also try:
=LET(a, TOCOL(A2:A, 1),
b, TOCOL(B2:B, 1),
c, TOCOL(C2:C, 1),
d, MAP(c, LAMBDA(x, IFNA(XLOOKUP(x, a, a), IF(WEEKDAY(XLOOKUP(x, b, b), 2) > 5, WORKDAY(XLOOKUP(x, b, b), 1, c), XLOOKUP(x, b, b))))),
SCAN("", d, LAMBDA(x, y, IF(COUNTIF(d, y) > 1, IF(x = y, WORKDAY(y, 1, c), y), y))))
A | B | C | D |
---|---|---|---|
9/26/2025 | 10/4/2025 | 9/26/2025 | 9/26/2025 |
11/10/2025 | 10/18/2025 | 10/4/2025 | 10/6/2025 |
11/12/2025 | 10/19/2025 | 10/18/2025 | 10/21/2025 |
11/13/2025 | 10/20/2025 | 10/19/2025 | 10/22/2025 |
11/17/2025 | 11/8/2025 | 10/20/2025 | 10/20/2025 |
1/1/2029 | 11/9/2025 | 11/8/2025 | 11/14/2025 |
1/7/2029 | 11/11/2025 | 11/9/2025 | 11/18/2025 |
1/8/2029 | 12/7/2025 | 11/10/2025 | 11/10/2025 |
1/9/2029 | 12/31/2028 | 11/11/2025 | 11/11/2025 |
1/6/2029 | 11/12/2025 | 11/12/2025 | |
1/10/2029 | 11/13/2025 | 11/13/2025 | |
11/17/2025 | 11/17/2025 | ||
12/7/2025 | 12/8/2025 | ||
12/31/2028 | 1/2/2029 | ||
1/1/2029 | 1/1/2029 | ||
1/6/2029 | 1/11/2029 | ||
1/7/2029 | 1/7/2029 | ||
1/8/2029 | 1/8/2029 | ||
1/9/2029 | 1/9/2029 | ||
1/10/2029 | 1/10/2029 |
Note: The MAP function can be changed to the BYROW function, and it should produce the same result.