FAILURE MAP
← Case archive

FA-77271 / Calendar recurrence rules / Open access

Closed-form final date of a COUNT-limited weekly BYDAY series: empty count · case 01

COUNT=0 reports a final date although the series is empty.

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

ROOT CAUSE

Only negative counts are treated as an empty series.

VERIFIED REPAIR

At the empty count decision use `count < 1`, leaving the other decision sites of the model unchanged.

Unsuccessful approach: The partial repair `count == 0` handles zero but a negative count still yields a date.

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 < 0:
        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)],
 [('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'),
  ('count zero', ['2024-01-01', 1, [0], 0, 0], None)],
 [('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'),
  ('count zero', ['2024-01-01', 1, [0], 0, 0], None),
  ('count negative', ['2024-01-01', 2, [0, 3], 0, -1], None)]]
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 zero2024-01-01NoneFailed
count negativeNoneNonePassed

SHA-256 / dd2e6da172ce2c0f50292aef75cdf4a4b643bceb6b952ce94b5f5419b0e15d8f

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 == 0:
        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)],
 [('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'),
  ('count zero', ['2024-01-01', 1, [0], 0, 0], None)],
 [('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'),
  ('count zero', ['2024-01-01', 1, [0], 0, 0], None),
  ('count negative', ['2024-01-01', 2, [0, 3], 0, -1], None)]]
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 negative2024-01-01NoneFailed

SHA-256 / 0186378e00dffc5054fc292df1231337d8657d5f382441a01c9f2bf18f79c111

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)],
 [('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'),
  ('count zero', ['2024-01-01', 1, [0], 0, 0], None)],
 [('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'),
  ('count zero', ['2024-01-01', 1, [0], 0, 0], None),
  ('count negative', ['2024-01-01', 2, [0, 3], 0, -1], None)]]
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

SHA-256 / 11ec558024551a2737205d52a5df27387996acd0e6a1462eed581e8e84e3d94b

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:23.911816+00:00.

Case digest / 8db78af70ee6a6dce6eb3591fcf3985a8cf71bf3aec16c4ec05692a09c41b945