FAILURE MAP
← Case archive

FA-77276 / Calendar recurrence rules / Open access

Closed-form final date of a COUNT-limited weekly BYDAY series: first week filter · case 01

With WKST=SU a Sunday in the first week is miscounted and the end date shifts by a week.

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

ROOT CAUSE

The partial first week is computed with Monday-based weekday numbers.

VERIFIED REPAIR

At the first week filter decision use `(w - wkst) % 7 >= (start.weekday() - wkst) % 7`, leaving the other decision sites of the model unchanged.

Unsuccessful approach: The partial repair `(w - wkst) % 7 > (start.weekday() - wkst) % 7` uses a strict comparison and so excludes dtstart itself from the first week.

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 >= start.weekday()]
    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')],
 [('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-191997-08-31Failed
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 / 3cefd099f8a300f835e35078b9b773e4224923f00d0ecc4c9fa72df337601978

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(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')],
 [('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-09-021997-08-24Failed
multiple of weekday count2024-01-152024-01-12Failed
partial first week2024-01-152024-01-15Passed
interval 3 single day2024-06-212024-06-21Passed
count zeroNoneNonePassed
count negativeNoneNonePassed

SHA-256 / 25781d33abd10afc77ca323236add14e46c9d80516dfbe34af5c9ff7a211c96e

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')],
 [('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

SHA-256 / 5e3cc88b9e616003c941ed28c01fecfbe205d3c262a210332f6a838bda8f05bc

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

Case digest / fdb18f5e27fe881b7137f9afc542760ab1c5878a1d57489fa03a1bf3bc5eae14