FAILURE MAP
← Case archive

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.

Verified by executionVariant 1 · 8 checks per implementationDownload source bundle ↓JSON ↗

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 fixtureActualExpectedOutcome
regression: WKST=SU interval 2 TU,SU1997-09-021997-08-31Failed
WKST=MO interval 2 TU,SU1997-08-191997-08-24Failed
multiple of weekday count2024-01-082024-01-12Failed
partial first week2024-01-172024-01-15Failed
interval 3 single day2024-06-212024-06-21Passed
count zeroNoneNonePassed
count negativeNoneNonePassed
WKST=SU weekend2024-03-172024-03-23Failed

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 fixtureActualExpectedOutcome
regression: WKST=SU interval 2 TU,SU1997-08-311997-08-31Passed
WKST=MO interval 2 TU,SU1997-08-241997-08-24Passed
multiple of weekday count2024-01-122024-01-12Passed
partial first week2024-01-152024-01-15Passed
interval 3 single day2024-06-212024-06-21Passed
count zeroNoneNonePassed
count negativeNoneNonePassed
WKST=SU weekend2024-03-172024-03-23Failed

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 fixtureActualExpectedOutcome
regression: WKST=SU interval 2 TU,SU1997-08-311997-08-31Passed
WKST=MO interval 2 TU,SU1997-08-241997-08-24Passed
multiple of weekday count2024-01-122024-01-12Passed
partial first week2024-01-152024-01-15Passed
interval 3 single day2024-06-212024-06-21Passed
count zeroNoneNonePassed
count negativeNoneNonePassed
WKST=SU weekend2024-03-232024-03-23Passed

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