FA-77286 / Calendar recurrence rules / Open access
Closed-form final date of a COUNT-limited weekly BYDAY series: remainder index · case 01
The final weekday is one position too late in the week pattern.
ROOT CAUSE
The remainder is taken without the 1-based adjustment.
VERIFIED REPAIR
At the remainder index decision use `(rest - 1) % len(days)`, leaving the other decision sites of the model unchanged.
Unsuccessful approach: The partial repair `(rest - 1) % len(first_week or days)` takes the remainder modulo the partial first week size.
Case contract
For FREQ=WEEKLY;INTERVAL;BYDAY;WKST;COUNT starting at dtstart (weeks begin on wkst, days of the first week before dtstart are skipped, active weeks every interval weeks from the dtstart week), compute the date of the final instance arithmetically, without expanding. count < 1 returns None. The result must equal the last element of the full expansion.
Why this case matters
Recurring calendar series are expanded into concrete instances for display, reminders and conflict checks.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import datetime as dt
import calendar
N = 1
observations = []
def solve(dtstart, interval, byday, wkst, count):
start = dt.date.fromisoformat(dtstart)
if count < 1:
return None
days = sorted(set(byday), key=lambda w: (w - wkst) % 7)
week0 = start - dt.timedelta(days=(start.weekday() - wkst) % 7)
first_week = [w for w in days if (w - wkst) % 7 >= (start.weekday() - wkst) % 7]
if count <= len(first_week):
w = first_week[count - 1]
weeks = 0
else:
rest = count - len(first_week)
weeks = (rest - 1) // len(days) + 1
w = days[rest % len(days)]
last = week0 + dt.timedelta(days=weeks * interval * 7 + (w - wkst) % 7)
return last.isoformat()
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: WKST=SU interval 2 TU,SU', ['1997-08-05', 2, [1, 6], 6, 4], '1997-08-31'),
('WKST=MO interval 2 TU,SU', ['1997-08-05', 2, [1, 6], 0, 4], '1997-08-24'),
('multiple of weekday count', ['2024-01-01', 1, [0, 2, 4], 0, 6], '2024-01-12'),
('partial first week', ['2024-01-04', 1, [0, 2, 4], 0, 5], '2024-01-15'),
('interval 3 single day', ['2024-05-06', 3, [4], 0, 3], '2024-06-21'),
('count zero', ['2024-01-01', 1, [0], 0, 0], None),
('count negative', ['2024-01-01', 2, [0, 3], 0, -1], None),
('WKST=SU weekend', ['2024-03-09', 1, [5, 6], 6, 5], '2024-03-23')],
[('multiple of weekday count', ['2024-01-01', 1, [0, 2, 4], 0, 6], '2024-01-12'),
('partial first week', ['2024-01-04', 1, [0, 2, 4], 0, 5], '2024-01-15'),
('interval 3 single day', ['2024-05-06', 3, [4], 0, 3], '2024-06-21'),
('count zero', ['2024-01-01', 1, [0], 0, 0], None),
('count negative', ['2024-01-01', 2, [0, 3], 0, -1], None),
('within first week', ['2024-01-01', 2, [0, 1, 2], 0, 2], '2024-01-02'),
('WKST=SU weekend', ['2024-03-09', 1, [5, 6], 6, 5], '2024-03-23')],
[('interval 3 single day', ['2024-05-06', 3, [4], 0, 3], '2024-06-21'),
('count zero', ['2024-01-01', 1, [0], 0, 0], None),
('count negative', ['2024-01-01', 2, [0, 3], 0, -1], None),
('within first week', ['2024-01-01', 2, [0, 1, 2], 0, 2], '2024-01-02'),
('WKST=SU weekend', ['2024-03-09', 1, [5, 6], 6, 5], '2024-03-23'),
('WKST=WE interval 2', ['2024-06-04', 2, [0, 3], 2, 7], '2024-07-25'),
('dtstart after all first-week days', ['2024-01-06', 2, [0, 1], 0, 5], '2024-02-12')],
[('count negative', ['2024-01-01', 2, [0, 3], 0, -1], None),
('within first week', ['2024-01-01', 2, [0, 1, 2], 0, 2], '2024-01-02'),
('WKST=SU weekend', ['2024-03-09', 1, [5, 6], 6, 5], '2024-03-23'),
('WKST=WE interval 2', ['2024-06-04', 2, [0, 3], 2, 7], '2024-07-25'),
('dtstart after all first-week days', ['2024-01-06', 2, [0, 1], 0, 5], '2024-02-12'),
('long series', ['2025-02-03', 2, [1, 3, 5], 0, 11], '2025-03-20'),
('regression: WKST=SU interval 2 TU,SU', ['1997-08-05', 2, [1, 6], 6, 4], '1997-08-31')],
[('WKST=SU weekend', ['2024-03-09', 1, [5, 6], 6, 5], '2024-03-23'),
('WKST=WE interval 2', ['2024-06-04', 2, [0, 3], 2, 7], '2024-07-25'),
('dtstart after all first-week days', ['2024-01-06', 2, [0, 1], 0, 5], '2024-02-12'),
('long series', ['2025-02-03', 2, [1, 3, 5], 0, 11], '2025-03-20'),
('regression: WKST=SU interval 2 TU,SU', ['1997-08-05', 2, [1, 6], 6, 4], '1997-08-31'),
('WKST=MO interval 2 TU,SU', ['1997-08-05', 2, [1, 6], 0, 4], '1997-08-24'),
('multiple of weekday count', ['2024-01-01', 1, [0, 2, 4], 0, 6], '2024-01-12')]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: WKST=SU interval 2 TU,SU | 1997-09-02 | 1997-08-31 | Failed |
| WKST=MO interval 2 TU,SU | 1997-08-19 | 1997-08-24 | Failed |
| multiple of weekday count | 2024-01-08 | 2024-01-12 | Failed |
| partial first week | 2024-01-17 | 2024-01-15 | Failed |
| interval 3 single day | 2024-06-21 | 2024-06-21 | Passed |
| count zero | None | None | Passed |
| count negative | None | None | Passed |
| WKST=SU weekend | 2024-03-17 | 2024-03-23 | Failed |
SHA-256 / c85a2d1359801a68ebadc2f6602a64954020e7d9693b4a79e7dd9678751c6d59
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import datetime as dt
import calendar
N = 1
observations = []
def solve(dtstart, interval, byday, wkst, count):
start = dt.date.fromisoformat(dtstart)
if count < 1:
return None
days = sorted(set(byday), key=lambda w: (w - wkst) % 7)
week0 = start - dt.timedelta(days=(start.weekday() - wkst) % 7)
first_week = [w for w in days if (w - wkst) % 7 >= (start.weekday() - wkst) % 7]
if count <= len(first_week):
w = first_week[count - 1]
weeks = 0
else:
rest = count - len(first_week)
weeks = (rest - 1) // len(days) + 1
w = days[(rest - 1) % len(first_week or days)]
last = week0 + dt.timedelta(days=weeks * interval * 7 + (w - wkst) % 7)
return last.isoformat()
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: WKST=SU interval 2 TU,SU', ['1997-08-05', 2, [1, 6], 6, 4], '1997-08-31'),
('WKST=MO interval 2 TU,SU', ['1997-08-05', 2, [1, 6], 0, 4], '1997-08-24'),
('multiple of weekday count', ['2024-01-01', 1, [0, 2, 4], 0, 6], '2024-01-12'),
('partial first week', ['2024-01-04', 1, [0, 2, 4], 0, 5], '2024-01-15'),
('interval 3 single day', ['2024-05-06', 3, [4], 0, 3], '2024-06-21'),
('count zero', ['2024-01-01', 1, [0], 0, 0], None),
('count negative', ['2024-01-01', 2, [0, 3], 0, -1], None),
('WKST=SU weekend', ['2024-03-09', 1, [5, 6], 6, 5], '2024-03-23')],
[('multiple of weekday count', ['2024-01-01', 1, [0, 2, 4], 0, 6], '2024-01-12'),
('partial first week', ['2024-01-04', 1, [0, 2, 4], 0, 5], '2024-01-15'),
('interval 3 single day', ['2024-05-06', 3, [4], 0, 3], '2024-06-21'),
('count zero', ['2024-01-01', 1, [0], 0, 0], None),
('count negative', ['2024-01-01', 2, [0, 3], 0, -1], None),
('within first week', ['2024-01-01', 2, [0, 1, 2], 0, 2], '2024-01-02'),
('WKST=SU weekend', ['2024-03-09', 1, [5, 6], 6, 5], '2024-03-23')],
[('interval 3 single day', ['2024-05-06', 3, [4], 0, 3], '2024-06-21'),
('count zero', ['2024-01-01', 1, [0], 0, 0], None),
('count negative', ['2024-01-01', 2, [0, 3], 0, -1], None),
('within first week', ['2024-01-01', 2, [0, 1, 2], 0, 2], '2024-01-02'),
('WKST=SU weekend', ['2024-03-09', 1, [5, 6], 6, 5], '2024-03-23'),
('WKST=WE interval 2', ['2024-06-04', 2, [0, 3], 2, 7], '2024-07-25'),
('dtstart after all first-week days', ['2024-01-06', 2, [0, 1], 0, 5], '2024-02-12')],
[('count negative', ['2024-01-01', 2, [0, 3], 0, -1], None),
('within first week', ['2024-01-01', 2, [0, 1, 2], 0, 2], '2024-01-02'),
('WKST=SU weekend', ['2024-03-09', 1, [5, 6], 6, 5], '2024-03-23'),
('WKST=WE interval 2', ['2024-06-04', 2, [0, 3], 2, 7], '2024-07-25'),
('dtstart after all first-week days', ['2024-01-06', 2, [0, 1], 0, 5], '2024-02-12'),
('long series', ['2025-02-03', 2, [1, 3, 5], 0, 11], '2025-03-20'),
('regression: WKST=SU interval 2 TU,SU', ['1997-08-05', 2, [1, 6], 6, 4], '1997-08-31')],
[('WKST=SU weekend', ['2024-03-09', 1, [5, 6], 6, 5], '2024-03-23'),
('WKST=WE interval 2', ['2024-06-04', 2, [0, 3], 2, 7], '2024-07-25'),
('dtstart after all first-week days', ['2024-01-06', 2, [0, 1], 0, 5], '2024-02-12'),
('long series', ['2025-02-03', 2, [1, 3, 5], 0, 11], '2025-03-20'),
('regression: WKST=SU interval 2 TU,SU', ['1997-08-05', 2, [1, 6], 6, 4], '1997-08-31'),
('WKST=MO interval 2 TU,SU', ['1997-08-05', 2, [1, 6], 0, 4], '1997-08-24'),
('multiple of weekday count', ['2024-01-01', 1, [0, 2, 4], 0, 6], '2024-01-12')]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: WKST=SU interval 2 TU,SU | 1997-08-31 | 1997-08-31 | Passed |
| WKST=MO interval 2 TU,SU | 1997-08-24 | 1997-08-24 | Passed |
| multiple of weekday count | 2024-01-12 | 2024-01-12 | Passed |
| partial first week | 2024-01-15 | 2024-01-15 | Passed |
| interval 3 single day | 2024-06-21 | 2024-06-21 | Passed |
| count zero | None | None | Passed |
| count negative | None | None | Passed |
| WKST=SU weekend | 2024-03-17 | 2024-03-23 | Failed |
SHA-256 / bbfff17fc73cb9770fa1e9e77d7b84119c519c16251b05a00f5ca876f8560958
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import datetime as dt
import calendar
N = 1
observations = []
def solve(dtstart, interval, byday, wkst, count):
start = dt.date.fromisoformat(dtstart)
if count < 1:
return None
days = sorted(set(byday), key=lambda w: (w - wkst) % 7)
week0 = start - dt.timedelta(days=(start.weekday() - wkst) % 7)
first_week = [w for w in days if (w - wkst) % 7 >= (start.weekday() - wkst) % 7]
if count <= len(first_week):
w = first_week[count - 1]
weeks = 0
else:
rest = count - len(first_week)
weeks = (rest - 1) // len(days) + 1
w = days[(rest - 1) % len(days)]
last = week0 + dt.timedelta(days=weeks * interval * 7 + (w - wkst) % 7)
return last.isoformat()
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: WKST=SU interval 2 TU,SU', ['1997-08-05', 2, [1, 6], 6, 4], '1997-08-31'),
('WKST=MO interval 2 TU,SU', ['1997-08-05', 2, [1, 6], 0, 4], '1997-08-24'),
('multiple of weekday count', ['2024-01-01', 1, [0, 2, 4], 0, 6], '2024-01-12'),
('partial first week', ['2024-01-04', 1, [0, 2, 4], 0, 5], '2024-01-15'),
('interval 3 single day', ['2024-05-06', 3, [4], 0, 3], '2024-06-21'),
('count zero', ['2024-01-01', 1, [0], 0, 0], None),
('count negative', ['2024-01-01', 2, [0, 3], 0, -1], None),
('WKST=SU weekend', ['2024-03-09', 1, [5, 6], 6, 5], '2024-03-23')],
[('multiple of weekday count', ['2024-01-01', 1, [0, 2, 4], 0, 6], '2024-01-12'),
('partial first week', ['2024-01-04', 1, [0, 2, 4], 0, 5], '2024-01-15'),
('interval 3 single day', ['2024-05-06', 3, [4], 0, 3], '2024-06-21'),
('count zero', ['2024-01-01', 1, [0], 0, 0], None),
('count negative', ['2024-01-01', 2, [0, 3], 0, -1], None),
('within first week', ['2024-01-01', 2, [0, 1, 2], 0, 2], '2024-01-02'),
('WKST=SU weekend', ['2024-03-09', 1, [5, 6], 6, 5], '2024-03-23')],
[('interval 3 single day', ['2024-05-06', 3, [4], 0, 3], '2024-06-21'),
('count zero', ['2024-01-01', 1, [0], 0, 0], None),
('count negative', ['2024-01-01', 2, [0, 3], 0, -1], None),
('within first week', ['2024-01-01', 2, [0, 1, 2], 0, 2], '2024-01-02'),
('WKST=SU weekend', ['2024-03-09', 1, [5, 6], 6, 5], '2024-03-23'),
('WKST=WE interval 2', ['2024-06-04', 2, [0, 3], 2, 7], '2024-07-25'),
('dtstart after all first-week days', ['2024-01-06', 2, [0, 1], 0, 5], '2024-02-12')],
[('count negative', ['2024-01-01', 2, [0, 3], 0, -1], None),
('within first week', ['2024-01-01', 2, [0, 1, 2], 0, 2], '2024-01-02'),
('WKST=SU weekend', ['2024-03-09', 1, [5, 6], 6, 5], '2024-03-23'),
('WKST=WE interval 2', ['2024-06-04', 2, [0, 3], 2, 7], '2024-07-25'),
('dtstart after all first-week days', ['2024-01-06', 2, [0, 1], 0, 5], '2024-02-12'),
('long series', ['2025-02-03', 2, [1, 3, 5], 0, 11], '2025-03-20'),
('regression: WKST=SU interval 2 TU,SU', ['1997-08-05', 2, [1, 6], 6, 4], '1997-08-31')],
[('WKST=SU weekend', ['2024-03-09', 1, [5, 6], 6, 5], '2024-03-23'),
('WKST=WE interval 2', ['2024-06-04', 2, [0, 3], 2, 7], '2024-07-25'),
('dtstart after all first-week days', ['2024-01-06', 2, [0, 1], 0, 5], '2024-02-12'),
('long series', ['2025-02-03', 2, [1, 3, 5], 0, 11], '2025-03-20'),
('regression: WKST=SU interval 2 TU,SU', ['1997-08-05', 2, [1, 6], 6, 4], '1997-08-31'),
('WKST=MO interval 2 TU,SU', ['1997-08-05', 2, [1, 6], 0, 4], '1997-08-24'),
('multiple of weekday count', ['2024-01-01', 1, [0, 2, 4], 0, 6], '2024-01-12')]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: WKST=SU interval 2 TU,SU | 1997-08-31 | 1997-08-31 | Passed |
| WKST=MO interval 2 TU,SU | 1997-08-24 | 1997-08-24 | Passed |
| multiple of weekday count | 2024-01-12 | 2024-01-12 | Passed |
| partial first week | 2024-01-15 | 2024-01-15 | Passed |
| interval 3 single day | 2024-06-21 | 2024-06-21 | Passed |
| count zero | None | None | Passed |
| count negative | None | None | Passed |
| WKST=SU weekend | 2024-03-23 | 2024-03-23 | Passed |
SHA-256 / d8bd55db9bd0f9ff10966ed4deade1727dd52be19414a9ab7114863e25881999
Verification & scope
Stipulated, bounded recurrence-expansion model evaluated offline on explicit fixtures; it is not a complete iCalendar implementation and makes no claim of standards conformance. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.
Observations recorded using Python 3.12.14 at 2026-09-29T14:49:24.236309+00:00.
Case digest / fd203e899d14a991c3a98035db21b8150afcdf67453128915b47ede4dda4f2ad