FA-77111 / Calendar recurrence rules / Open access
Yearly ISO BYWEEKNO/BYDAY expansion: week one monday · case 01
In years starting on Friday, Saturday or Sunday every week number is one week early.
ROOT CAUSE
Week 1 is taken as the week containing January 1.
VERIFIED REPAIR
At the week one monday decision use `jan4 - dt.timedelta(days=jan4.weekday())`, leaving the other decision sites of the model unchanged.
Unsuccessful approach: The partial repair `jan4 - dt.timedelta(days=(jan4.weekday() + 1) % 7)` aligns weeks to Sunday instead of Monday.
Case contract
FREQ=YEARLY with BYWEEKNO (ISO weeks, Monday start, week 1 contains January 4) and BYDAY weekdays (0=Monday). Negative week numbers count from the last ISO week of the year (-1 is the last). A year has 53 weeks exactly when December 28 falls in week 53; week numbers outside 1..weeks are ignored for that year. Dates may fall in the adjacent calendar year. Expand years year_start .. year_start+years-1 and return unique ISO dates sorted.
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(year_start, weeknos, weekdays, years):
out = set()
for y in range(year_start, year_start + years):
jan4 = dt.date(y, 1, 4)
week1 = dt.date(y, 1, 1) - dt.timedelta(days=dt.date(y, 1, 1).weekday())
nweeks = dt.date(y, 12, 28).isocalendar()[1]
for wn in weeknos:
w = wn if wn > 0 else nweeks + wn + 1
if not (1 <= w <= nweeks):
continue
for wd in weekdays:
out.add(week1 + dt.timedelta(days=(w - 1) * 7 + wd))
return sorted(d.isoformat() for d in out)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: week 1 in 2021', [2021, [1], [0], 1], ['2021-01-04']),
('week 53 existence', [2019, [53], [0], 3], ['2020-12-28']),
('last week negative', [2020, [-1], [6], 3], ['2021-01-03', '2022-01-02', '2023-01-01']),
('leap year starting wednesday', [2024, [-1, 53], [0], 2], ['2024-12-23', '2025-12-22']),
('week 20 monday friday',
[2023, [20], [0, 4], 2],
['2023-05-15', '2023-05-19', '2024-05-13', '2024-05-17']),
('too-negative week', [2021, [-60, 2], [2], 1], ['2021-01-13']),
('week 1 sunday spans years',
[2015, [1, 52], [6], 2],
['2015-01-04', '2015-12-27', '2016-01-10', '2017-01-01'])],
[('last week negative', [2020, [-1], [6], 3], ['2021-01-03', '2022-01-02', '2023-01-01']),
('leap year starting wednesday', [2024, [-1, 53], [0], 2], ['2024-12-23', '2025-12-22']),
('week 20 monday friday',
[2023, [20], [0, 4], 2],
['2023-05-15', '2023-05-19', '2024-05-13', '2024-05-17']),
('too-negative week', [2021, [-60, 2], [2], 1], ['2021-01-13']),
('week 1 sunday spans years',
[2015, [1, 52], [6], 2],
['2015-01-04', '2015-12-27', '2016-01-10', '2017-01-01']),
('second to last week', [2026, [-2], [3], 2], ['2026-12-24', '2027-12-23']),
('many weeks', [2027, [1, -1, 26], [0], 1], ['2027-01-04', '2027-06-28', '2027-12-27'])],
[('week 20 monday friday',
[2023, [20], [0, 4], 2],
['2023-05-15', '2023-05-19', '2024-05-13', '2024-05-17']),
('too-negative week', [2021, [-60, 2], [2], 1], ['2021-01-13']),
('week 1 sunday spans years',
[2015, [1, 52], [6], 2],
['2015-01-04', '2015-12-27', '2016-01-10', '2017-01-01']),
('second to last week', [2026, [-2], [3], 2], ['2026-12-24', '2027-12-23']),
('many weeks', [2027, [1, -1, 26], [0], 1], ['2027-01-04', '2027-06-28', '2027-12-27']),
('year starting saturday', [2022, [1, 53], [1, 5], 1], ['2022-01-04', '2022-01-08']),
('53 in 2026', [2026, [53], [4], 1], ['2027-01-01'])],
[('week 1 sunday spans years',
[2015, [1, 52], [6], 2],
['2015-01-04', '2015-12-27', '2016-01-10', '2017-01-01']),
('second to last week', [2026, [-2], [3], 2], ['2026-12-24', '2027-12-23']),
('many weeks', [2027, [1, -1, 26], [0], 1], ['2027-01-04', '2027-06-28', '2027-12-27']),
('year starting saturday', [2022, [1, 53], [1, 5], 1], ['2022-01-04', '2022-01-08']),
('53 in 2026', [2026, [53], [4], 1], ['2027-01-01']),
('regression: week 1 in 2021', [2021, [1], [0], 1], ['2021-01-04']),
('week 53 existence', [2019, [53], [0], 3], ['2020-12-28'])],
[('many weeks', [2027, [1, -1, 26], [0], 1], ['2027-01-04', '2027-06-28', '2027-12-27']),
('year starting saturday', [2022, [1, 53], [1, 5], 1], ['2022-01-04', '2022-01-08']),
('53 in 2026', [2026, [53], [4], 1], ['2027-01-01']),
('regression: week 1 in 2021', [2021, [1], [0], 1], ['2021-01-04']),
('week 53 existence', [2019, [53], [0], 3], ['2020-12-28']),
('last week negative', [2020, [-1], [6], 3], ['2021-01-03', '2022-01-02', '2023-01-01']),
('leap year starting wednesday', [2024, [-1, 53], [0], 2], ['2024-12-23', '2025-12-22'])]]
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: week 1 in 2021 | ['2020-12-28'] | ['2021-01-04'] | Failed |
| week 53 existence | ['2020-12-28'] | ['2020-12-28'] | Passed |
| last week negative | ['2021-01-03', '2021-12-26', '2022-12-25'] | ['2021-01-03', '2022-01-02', '2023-01-01'] | Failed |
| leap year starting wednesday | ['2024-12-23', '2025-12-22'] | ['2024-12-23', '2025-12-22'] | Passed |
| week 20 monday friday | ['2023-05-08', '2023-05-12', '2024-05-13', '2024-05-17'] | ['2023-05-15', '2023-05-19', '2024-05-13', '2024-05-17'] | Failed |
| too-negative week | ['2021-01-06'] | ['2021-01-13'] | Failed |
| week 1 sunday spans years | ['2015-01-04', '2015-12-27', '2016-01-03', '2016-12-25'] | ['2015-01-04', '2015-12-27', '2016-01-10', '2017-01-01'] | Failed |
SHA-256 / 60270fef1cd72d43119e744e79c821095530e4a971af6eb6511da6e41fe3235e
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(year_start, weeknos, weekdays, years):
out = set()
for y in range(year_start, year_start + years):
jan4 = dt.date(y, 1, 4)
week1 = jan4 - dt.timedelta(days=(jan4.weekday() + 1) % 7)
nweeks = dt.date(y, 12, 28).isocalendar()[1]
for wn in weeknos:
w = wn if wn > 0 else nweeks + wn + 1
if not (1 <= w <= nweeks):
continue
for wd in weekdays:
out.add(week1 + dt.timedelta(days=(w - 1) * 7 + wd))
return sorted(d.isoformat() for d in out)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: week 1 in 2021', [2021, [1], [0], 1], ['2021-01-04']),
('week 53 existence', [2019, [53], [0], 3], ['2020-12-28']),
('last week negative', [2020, [-1], [6], 3], ['2021-01-03', '2022-01-02', '2023-01-01']),
('leap year starting wednesday', [2024, [-1, 53], [0], 2], ['2024-12-23', '2025-12-22']),
('week 20 monday friday',
[2023, [20], [0, 4], 2],
['2023-05-15', '2023-05-19', '2024-05-13', '2024-05-17']),
('too-negative week', [2021, [-60, 2], [2], 1], ['2021-01-13']),
('week 1 sunday spans years',
[2015, [1, 52], [6], 2],
['2015-01-04', '2015-12-27', '2016-01-10', '2017-01-01'])],
[('last week negative', [2020, [-1], [6], 3], ['2021-01-03', '2022-01-02', '2023-01-01']),
('leap year starting wednesday', [2024, [-1, 53], [0], 2], ['2024-12-23', '2025-12-22']),
('week 20 monday friday',
[2023, [20], [0, 4], 2],
['2023-05-15', '2023-05-19', '2024-05-13', '2024-05-17']),
('too-negative week', [2021, [-60, 2], [2], 1], ['2021-01-13']),
('week 1 sunday spans years',
[2015, [1, 52], [6], 2],
['2015-01-04', '2015-12-27', '2016-01-10', '2017-01-01']),
('second to last week', [2026, [-2], [3], 2], ['2026-12-24', '2027-12-23']),
('many weeks', [2027, [1, -1, 26], [0], 1], ['2027-01-04', '2027-06-28', '2027-12-27'])],
[('week 20 monday friday',
[2023, [20], [0, 4], 2],
['2023-05-15', '2023-05-19', '2024-05-13', '2024-05-17']),
('too-negative week', [2021, [-60, 2], [2], 1], ['2021-01-13']),
('week 1 sunday spans years',
[2015, [1, 52], [6], 2],
['2015-01-04', '2015-12-27', '2016-01-10', '2017-01-01']),
('second to last week', [2026, [-2], [3], 2], ['2026-12-24', '2027-12-23']),
('many weeks', [2027, [1, -1, 26], [0], 1], ['2027-01-04', '2027-06-28', '2027-12-27']),
('year starting saturday', [2022, [1, 53], [1, 5], 1], ['2022-01-04', '2022-01-08']),
('53 in 2026', [2026, [53], [4], 1], ['2027-01-01'])],
[('week 1 sunday spans years',
[2015, [1, 52], [6], 2],
['2015-01-04', '2015-12-27', '2016-01-10', '2017-01-01']),
('second to last week', [2026, [-2], [3], 2], ['2026-12-24', '2027-12-23']),
('many weeks', [2027, [1, -1, 26], [0], 1], ['2027-01-04', '2027-06-28', '2027-12-27']),
('year starting saturday', [2022, [1, 53], [1, 5], 1], ['2022-01-04', '2022-01-08']),
('53 in 2026', [2026, [53], [4], 1], ['2027-01-01']),
('regression: week 1 in 2021', [2021, [1], [0], 1], ['2021-01-04']),
('week 53 existence', [2019, [53], [0], 3], ['2020-12-28'])],
[('many weeks', [2027, [1, -1, 26], [0], 1], ['2027-01-04', '2027-06-28', '2027-12-27']),
('year starting saturday', [2022, [1, 53], [1, 5], 1], ['2022-01-04', '2022-01-08']),
('53 in 2026', [2026, [53], [4], 1], ['2027-01-01']),
('regression: week 1 in 2021', [2021, [1], [0], 1], ['2021-01-04']),
('week 53 existence', [2019, [53], [0], 3], ['2020-12-28']),
('last week negative', [2020, [-1], [6], 3], ['2021-01-03', '2022-01-02', '2023-01-01']),
('leap year starting wednesday', [2024, [-1, 53], [0], 2], ['2024-12-23', '2025-12-22'])]]
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: week 1 in 2021 | ['2021-01-03'] | ['2021-01-04'] | Failed |
| week 53 existence | ['2020-12-27'] | ['2020-12-28'] | Failed |
| last week negative | ['2021-01-02', '2022-01-01', '2022-12-31'] | ['2021-01-03', '2022-01-02', '2023-01-01'] | Failed |
| leap year starting wednesday | ['2024-12-22', '2025-12-21'] | ['2024-12-23', '2025-12-22'] | Failed |
| week 20 monday friday | ['2023-05-14', '2023-05-18', '2024-05-12', '2024-05-16'] | ['2023-05-15', '2023-05-19', '2024-05-13', '2024-05-17'] | Failed |
| too-negative week | ['2021-01-12'] | ['2021-01-13'] | Failed |
| week 1 sunday spans years | ['2015-01-10', '2016-01-02', '2016-01-09', '2016-12-31'] | ['2015-01-04', '2015-12-27', '2016-01-10', '2017-01-01'] | Failed |
SHA-256 / 09a78635f52790696d0b891db878a82b87b7fbe7ce3a4b10cc406359c3aba309
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(year_start, weeknos, weekdays, years):
out = set()
for y in range(year_start, year_start + years):
jan4 = dt.date(y, 1, 4)
week1 = jan4 - dt.timedelta(days=jan4.weekday())
nweeks = dt.date(y, 12, 28).isocalendar()[1]
for wn in weeknos:
w = wn if wn > 0 else nweeks + wn + 1
if not (1 <= w <= nweeks):
continue
for wd in weekdays:
out.add(week1 + dt.timedelta(days=(w - 1) * 7 + wd))
return sorted(d.isoformat() for d in out)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: week 1 in 2021', [2021, [1], [0], 1], ['2021-01-04']),
('week 53 existence', [2019, [53], [0], 3], ['2020-12-28']),
('last week negative', [2020, [-1], [6], 3], ['2021-01-03', '2022-01-02', '2023-01-01']),
('leap year starting wednesday', [2024, [-1, 53], [0], 2], ['2024-12-23', '2025-12-22']),
('week 20 monday friday',
[2023, [20], [0, 4], 2],
['2023-05-15', '2023-05-19', '2024-05-13', '2024-05-17']),
('too-negative week', [2021, [-60, 2], [2], 1], ['2021-01-13']),
('week 1 sunday spans years',
[2015, [1, 52], [6], 2],
['2015-01-04', '2015-12-27', '2016-01-10', '2017-01-01'])],
[('last week negative', [2020, [-1], [6], 3], ['2021-01-03', '2022-01-02', '2023-01-01']),
('leap year starting wednesday', [2024, [-1, 53], [0], 2], ['2024-12-23', '2025-12-22']),
('week 20 monday friday',
[2023, [20], [0, 4], 2],
['2023-05-15', '2023-05-19', '2024-05-13', '2024-05-17']),
('too-negative week', [2021, [-60, 2], [2], 1], ['2021-01-13']),
('week 1 sunday spans years',
[2015, [1, 52], [6], 2],
['2015-01-04', '2015-12-27', '2016-01-10', '2017-01-01']),
('second to last week', [2026, [-2], [3], 2], ['2026-12-24', '2027-12-23']),
('many weeks', [2027, [1, -1, 26], [0], 1], ['2027-01-04', '2027-06-28', '2027-12-27'])],
[('week 20 monday friday',
[2023, [20], [0, 4], 2],
['2023-05-15', '2023-05-19', '2024-05-13', '2024-05-17']),
('too-negative week', [2021, [-60, 2], [2], 1], ['2021-01-13']),
('week 1 sunday spans years',
[2015, [1, 52], [6], 2],
['2015-01-04', '2015-12-27', '2016-01-10', '2017-01-01']),
('second to last week', [2026, [-2], [3], 2], ['2026-12-24', '2027-12-23']),
('many weeks', [2027, [1, -1, 26], [0], 1], ['2027-01-04', '2027-06-28', '2027-12-27']),
('year starting saturday', [2022, [1, 53], [1, 5], 1], ['2022-01-04', '2022-01-08']),
('53 in 2026', [2026, [53], [4], 1], ['2027-01-01'])],
[('week 1 sunday spans years',
[2015, [1, 52], [6], 2],
['2015-01-04', '2015-12-27', '2016-01-10', '2017-01-01']),
('second to last week', [2026, [-2], [3], 2], ['2026-12-24', '2027-12-23']),
('many weeks', [2027, [1, -1, 26], [0], 1], ['2027-01-04', '2027-06-28', '2027-12-27']),
('year starting saturday', [2022, [1, 53], [1, 5], 1], ['2022-01-04', '2022-01-08']),
('53 in 2026', [2026, [53], [4], 1], ['2027-01-01']),
('regression: week 1 in 2021', [2021, [1], [0], 1], ['2021-01-04']),
('week 53 existence', [2019, [53], [0], 3], ['2020-12-28'])],
[('many weeks', [2027, [1, -1, 26], [0], 1], ['2027-01-04', '2027-06-28', '2027-12-27']),
('year starting saturday', [2022, [1, 53], [1, 5], 1], ['2022-01-04', '2022-01-08']),
('53 in 2026', [2026, [53], [4], 1], ['2027-01-01']),
('regression: week 1 in 2021', [2021, [1], [0], 1], ['2021-01-04']),
('week 53 existence', [2019, [53], [0], 3], ['2020-12-28']),
('last week negative', [2020, [-1], [6], 3], ['2021-01-03', '2022-01-02', '2023-01-01']),
('leap year starting wednesday', [2024, [-1, 53], [0], 2], ['2024-12-23', '2025-12-22'])]]
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: week 1 in 2021 | ['2021-01-04'] | ['2021-01-04'] | Passed |
| week 53 existence | ['2020-12-28'] | ['2020-12-28'] | Passed |
| last week negative | ['2021-01-03', '2022-01-02', '2023-01-01'] | ['2021-01-03', '2022-01-02', '2023-01-01'] | Passed |
| leap year starting wednesday | ['2024-12-23', '2025-12-22'] | ['2024-12-23', '2025-12-22'] | Passed |
| week 20 monday friday | ['2023-05-15', '2023-05-19', '2024-05-13', '2024-05-17'] | ['2023-05-15', '2023-05-19', '2024-05-13', '2024-05-17'] | Passed |
| too-negative week | ['2021-01-13'] | ['2021-01-13'] | Passed |
| week 1 sunday spans years | ['2015-01-04', '2015-12-27', '2016-01-10', '2017-01-01'] | ['2015-01-04', '2015-12-27', '2016-01-10', '2017-01-01'] | Passed |
SHA-256 / 1bf8675221608a6eaa01e46aef10b50753f45fd6b34db88f615e16221044d69e
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:22.544793+00:00.
Case digest / c27b5b868ddb470d2ec1ee58f0c8536f3506cdb628a9a4aa316ba7236b37d10f