FA-77091 / Calendar recurrence rules / Open access
Daily BYHOUR/BYMINUTE time-of-day expansion: default hour · case 01
A rule with only BYMINUTE fires at midnight hours instead of the dtstart hour.
ROOT CAUSE
A missing BYHOUR defaults to hour 0.
VERIFIED REPAIR
At the default hour decision use `first.hour`, leaving the other decision sites of the model unchanged.
Unsuccessful approach: The partial repair `first.hour if byminute else 0` only defaults to the dtstart hour when BYMINUTE is present.
Case contract
FREQ=DAILY. Each day produces the cartesian product of BYHOUR and BYMINUTE in chronological order; a missing BYHOUR defaults to the dtstart hour and a missing BYMINUTE to the dtstart minute. Duplicates in either list are ignored. Times before dtstart are dropped. Return the first count ISO date-times.
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, byhour, byminute, count):
first = dt.datetime.fromisoformat(dtstart)
hours = sorted(set(byhour)) if byhour else [0]
minutes = sorted(set(byminute)) if byminute else [first.minute]
out = []
for k in range(400):
day = first.date() + dt.timedelta(days=k)
for h, mi in [(h, mi) for h in hours for mi in minutes]:
t = dt.datetime.combine(day, dt.time(h, mi))
if t < first:
continue
if len(out) >= count:
return out
out.append(t.isoformat(timespec='minutes'))
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: default minute from dtstart',
['2024-01-01T09:30', [9, 17], [], 4],
['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30']),
('only byminute',
['2024-01-01T14:10', [], [0, 30], 4],
['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00']),
('unsorted duplicate hours',
['2024-01-01T08:00', [17, 9, 17], [15], 4],
['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15']),
('product of two lists',
['2024-01-01T00:00', [9, 13], [0, 45], 5],
['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00']),
('dtstart after some slots',
['2024-01-02T12:00', [8, 12, 18], [0], 4],
['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00']),
('dtstart between minutes',
['2024-01-02T12:20', [12], [0, 20, 40], 4],
['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20']),
('three by three',
['2024-03-10T00:00', [6, 12, 18], [5, 10, 50], 7],
['2024-03-10T06:05',
'2024-03-10T06:10',
'2024-03-10T06:50',
'2024-03-10T12:05',
'2024-03-10T12:10',
'2024-03-10T12:50',
'2024-03-10T18:05']),
('no lists',
['2024-02-28T23:45', [], [], 3],
['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45'])],
[('unsorted duplicate hours',
['2024-01-01T08:00', [17, 9, 17], [15], 4],
['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15']),
('product of two lists',
['2024-01-01T00:00', [9, 13], [0, 45], 5],
['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00']),
('dtstart after some slots',
['2024-01-02T12:00', [8, 12, 18], [0], 4],
['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00']),
('dtstart between minutes',
['2024-01-02T12:20', [12], [0, 20, 40], 4],
['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20']),
('three by three',
['2024-03-10T00:00', [6, 12, 18], [5, 10, 50], 7],
['2024-03-10T06:05',
'2024-03-10T06:10',
'2024-03-10T06:50',
'2024-03-10T12:05',
'2024-03-10T12:10',
'2024-03-10T12:50',
'2024-03-10T18:05']),
('count zero', ['2024-01-01T09:00', [9], [0], 0], []),
('no lists',
['2024-02-28T23:45', [], [], 3],
['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45'])],
[('dtstart after some slots',
['2024-01-02T12:00', [8, 12, 18], [0], 4],
['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00']),
('dtstart between minutes',
['2024-01-02T12:20', [12], [0, 20, 40], 4],
['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20']),
('three by three',
['2024-03-10T00:00', [6, 12, 18], [5, 10, 50], 7],
['2024-03-10T06:05',
'2024-03-10T06:10',
'2024-03-10T06:50',
'2024-03-10T12:05',
'2024-03-10T12:10',
'2024-03-10T12:50',
'2024-03-10T18:05']),
('count zero', ['2024-01-01T09:00', [9], [0], 0], []),
('no lists', ['2024-02-28T23:45', [], [], 3], ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45']),
('unsorted minutes',
['2024-02-28T07:00', [7, 8], [50, 10], 5],
['2024-02-28T07:10', '2024-02-28T07:50', '2024-02-28T08:10', '2024-02-28T08:50', '2024-02-29T07:10']),
('late hour only list',
['2024-05-05T22:15', [23, 1], [], 4],
['2024-05-05T23:15', '2024-05-06T01:15', '2024-05-06T23:15', '2024-05-07T01:15'])],
[('three by three',
['2024-03-10T00:00', [6, 12, 18], [5, 10, 50], 7],
['2024-03-10T06:05',
'2024-03-10T06:10',
'2024-03-10T06:50',
'2024-03-10T12:05',
'2024-03-10T12:10',
'2024-03-10T12:50',
'2024-03-10T18:05']),
('count zero', ['2024-01-01T09:00', [9], [0], 0], []),
('no lists', ['2024-02-28T23:45', [], [], 3], ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45']),
('unsorted minutes',
['2024-02-28T07:00', [7, 8], [50, 10], 5],
['2024-02-28T07:10', '2024-02-28T07:50', '2024-02-28T08:10', '2024-02-28T08:50', '2024-02-29T07:10']),
('late hour only list',
['2024-05-05T22:15', [23, 1], [], 4],
['2024-05-05T23:15', '2024-05-06T01:15', '2024-05-06T23:15', '2024-05-07T01:15']),
('regression: default minute from dtstart',
['2024-01-01T09:30', [9, 17], [], 4],
['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30']),
('only byminute',
['2024-01-01T14:10', [], [0, 30], 4],
['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00'])],
[('no lists', ['2024-02-28T23:45', [], [], 3], ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45']),
('unsorted minutes',
['2024-02-28T07:00', [7, 8], [50, 10], 5],
['2024-02-28T07:10', '2024-02-28T07:50', '2024-02-28T08:10', '2024-02-28T08:50', '2024-02-29T07:10']),
('late hour only list',
['2024-05-05T22:15', [23, 1], [], 4],
['2024-05-05T23:15', '2024-05-06T01:15', '2024-05-06T23:15', '2024-05-07T01:15']),
('regression: default minute from dtstart',
['2024-01-01T09:30', [9, 17], [], 4],
['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30']),
('only byminute',
['2024-01-01T14:10', [], [0, 30], 4],
['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00']),
('unsorted duplicate hours',
['2024-01-01T08:00', [17, 9, 17], [15], 4],
['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15']),
('product of two lists',
['2024-01-01T00:00', [9, 13], [0, 45], 5],
['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00'])]]
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: default minute from dtstart | ['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30'] | ['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30'] | Passed |
| only byminute | ['2024-01-02T00:00', '2024-01-02T00:30', '2024-01-03T00:00', '2024-01-03T00:30'] | ['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00'] | Failed |
| unsorted duplicate hours | ['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15'] | ['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15'] | Passed |
| product of two lists | ['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00'] | ['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00'] | Passed |
| dtstart after some slots | ['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00'] | ['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00'] | Passed |
| dtstart between minutes | ['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20'] | ['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20'] | Passed |
| three by three | ['2024-03-10T06:05', '2024-03-10T06:10', '2024-03-10T06:50', '2024-03-10T12:05', '2024-03-10T12:10', '2024-03-10T12:50', '2024-03-10T18:05'] | ['2024-03-10T06:05', '2024-03-10T06:10', '2024-03-10T06:50', '2024-03-10T12:05', '2024-03-10T12:10', '2024-03-10T12:50', '2024-03-10T18:05'] | Passed |
| no lists | ['2024-02-29T00:45', '2024-03-01T00:45', '2024-03-02T00:45'] | ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45'] | Failed |
SHA-256 / 1e2b975eafeca3683e89ec55852dcdb7bc4a384e47131f8066cc7eb2ecc79751
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, byhour, byminute, count):
first = dt.datetime.fromisoformat(dtstart)
hours = sorted(set(byhour)) if byhour else [first.hour if byminute else 0]
minutes = sorted(set(byminute)) if byminute else [first.minute]
out = []
for k in range(400):
day = first.date() + dt.timedelta(days=k)
for h, mi in [(h, mi) for h in hours for mi in minutes]:
t = dt.datetime.combine(day, dt.time(h, mi))
if t < first:
continue
if len(out) >= count:
return out
out.append(t.isoformat(timespec='minutes'))
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: default minute from dtstart',
['2024-01-01T09:30', [9, 17], [], 4],
['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30']),
('only byminute',
['2024-01-01T14:10', [], [0, 30], 4],
['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00']),
('unsorted duplicate hours',
['2024-01-01T08:00', [17, 9, 17], [15], 4],
['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15']),
('product of two lists',
['2024-01-01T00:00', [9, 13], [0, 45], 5],
['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00']),
('dtstart after some slots',
['2024-01-02T12:00', [8, 12, 18], [0], 4],
['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00']),
('dtstart between minutes',
['2024-01-02T12:20', [12], [0, 20, 40], 4],
['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20']),
('three by three',
['2024-03-10T00:00', [6, 12, 18], [5, 10, 50], 7],
['2024-03-10T06:05',
'2024-03-10T06:10',
'2024-03-10T06:50',
'2024-03-10T12:05',
'2024-03-10T12:10',
'2024-03-10T12:50',
'2024-03-10T18:05']),
('no lists',
['2024-02-28T23:45', [], [], 3],
['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45'])],
[('unsorted duplicate hours',
['2024-01-01T08:00', [17, 9, 17], [15], 4],
['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15']),
('product of two lists',
['2024-01-01T00:00', [9, 13], [0, 45], 5],
['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00']),
('dtstart after some slots',
['2024-01-02T12:00', [8, 12, 18], [0], 4],
['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00']),
('dtstart between minutes',
['2024-01-02T12:20', [12], [0, 20, 40], 4],
['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20']),
('three by three',
['2024-03-10T00:00', [6, 12, 18], [5, 10, 50], 7],
['2024-03-10T06:05',
'2024-03-10T06:10',
'2024-03-10T06:50',
'2024-03-10T12:05',
'2024-03-10T12:10',
'2024-03-10T12:50',
'2024-03-10T18:05']),
('count zero', ['2024-01-01T09:00', [9], [0], 0], []),
('no lists',
['2024-02-28T23:45', [], [], 3],
['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45'])],
[('dtstart after some slots',
['2024-01-02T12:00', [8, 12, 18], [0], 4],
['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00']),
('dtstart between minutes',
['2024-01-02T12:20', [12], [0, 20, 40], 4],
['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20']),
('three by three',
['2024-03-10T00:00', [6, 12, 18], [5, 10, 50], 7],
['2024-03-10T06:05',
'2024-03-10T06:10',
'2024-03-10T06:50',
'2024-03-10T12:05',
'2024-03-10T12:10',
'2024-03-10T12:50',
'2024-03-10T18:05']),
('count zero', ['2024-01-01T09:00', [9], [0], 0], []),
('no lists', ['2024-02-28T23:45', [], [], 3], ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45']),
('unsorted minutes',
['2024-02-28T07:00', [7, 8], [50, 10], 5],
['2024-02-28T07:10', '2024-02-28T07:50', '2024-02-28T08:10', '2024-02-28T08:50', '2024-02-29T07:10']),
('late hour only list',
['2024-05-05T22:15', [23, 1], [], 4],
['2024-05-05T23:15', '2024-05-06T01:15', '2024-05-06T23:15', '2024-05-07T01:15'])],
[('three by three',
['2024-03-10T00:00', [6, 12, 18], [5, 10, 50], 7],
['2024-03-10T06:05',
'2024-03-10T06:10',
'2024-03-10T06:50',
'2024-03-10T12:05',
'2024-03-10T12:10',
'2024-03-10T12:50',
'2024-03-10T18:05']),
('count zero', ['2024-01-01T09:00', [9], [0], 0], []),
('no lists', ['2024-02-28T23:45', [], [], 3], ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45']),
('unsorted minutes',
['2024-02-28T07:00', [7, 8], [50, 10], 5],
['2024-02-28T07:10', '2024-02-28T07:50', '2024-02-28T08:10', '2024-02-28T08:50', '2024-02-29T07:10']),
('late hour only list',
['2024-05-05T22:15', [23, 1], [], 4],
['2024-05-05T23:15', '2024-05-06T01:15', '2024-05-06T23:15', '2024-05-07T01:15']),
('regression: default minute from dtstart',
['2024-01-01T09:30', [9, 17], [], 4],
['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30']),
('only byminute',
['2024-01-01T14:10', [], [0, 30], 4],
['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00'])],
[('no lists', ['2024-02-28T23:45', [], [], 3], ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45']),
('unsorted minutes',
['2024-02-28T07:00', [7, 8], [50, 10], 5],
['2024-02-28T07:10', '2024-02-28T07:50', '2024-02-28T08:10', '2024-02-28T08:50', '2024-02-29T07:10']),
('late hour only list',
['2024-05-05T22:15', [23, 1], [], 4],
['2024-05-05T23:15', '2024-05-06T01:15', '2024-05-06T23:15', '2024-05-07T01:15']),
('regression: default minute from dtstart',
['2024-01-01T09:30', [9, 17], [], 4],
['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30']),
('only byminute',
['2024-01-01T14:10', [], [0, 30], 4],
['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00']),
('unsorted duplicate hours',
['2024-01-01T08:00', [17, 9, 17], [15], 4],
['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15']),
('product of two lists',
['2024-01-01T00:00', [9, 13], [0, 45], 5],
['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00'])]]
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: default minute from dtstart | ['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30'] | ['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30'] | Passed |
| only byminute | ['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00'] | ['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00'] | Passed |
| unsorted duplicate hours | ['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15'] | ['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15'] | Passed |
| product of two lists | ['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00'] | ['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00'] | Passed |
| dtstart after some slots | ['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00'] | ['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00'] | Passed |
| dtstart between minutes | ['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20'] | ['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20'] | Passed |
| three by three | ['2024-03-10T06:05', '2024-03-10T06:10', '2024-03-10T06:50', '2024-03-10T12:05', '2024-03-10T12:10', '2024-03-10T12:50', '2024-03-10T18:05'] | ['2024-03-10T06:05', '2024-03-10T06:10', '2024-03-10T06:50', '2024-03-10T12:05', '2024-03-10T12:10', '2024-03-10T12:50', '2024-03-10T18:05'] | Passed |
| no lists | ['2024-02-29T00:45', '2024-03-01T00:45', '2024-03-02T00:45'] | ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45'] | Failed |
SHA-256 / 80a5d9a10e9e79f19c4f5b724b570e187e29992bf2fb10d902dbe682b686144d
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, byhour, byminute, count):
first = dt.datetime.fromisoformat(dtstart)
hours = sorted(set(byhour)) if byhour else [first.hour]
minutes = sorted(set(byminute)) if byminute else [first.minute]
out = []
for k in range(400):
day = first.date() + dt.timedelta(days=k)
for h, mi in [(h, mi) for h in hours for mi in minutes]:
t = dt.datetime.combine(day, dt.time(h, mi))
if t < first:
continue
if len(out) >= count:
return out
out.append(t.isoformat(timespec='minutes'))
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: default minute from dtstart',
['2024-01-01T09:30', [9, 17], [], 4],
['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30']),
('only byminute',
['2024-01-01T14:10', [], [0, 30], 4],
['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00']),
('unsorted duplicate hours',
['2024-01-01T08:00', [17, 9, 17], [15], 4],
['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15']),
('product of two lists',
['2024-01-01T00:00', [9, 13], [0, 45], 5],
['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00']),
('dtstart after some slots',
['2024-01-02T12:00', [8, 12, 18], [0], 4],
['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00']),
('dtstart between minutes',
['2024-01-02T12:20', [12], [0, 20, 40], 4],
['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20']),
('three by three',
['2024-03-10T00:00', [6, 12, 18], [5, 10, 50], 7],
['2024-03-10T06:05',
'2024-03-10T06:10',
'2024-03-10T06:50',
'2024-03-10T12:05',
'2024-03-10T12:10',
'2024-03-10T12:50',
'2024-03-10T18:05']),
('no lists',
['2024-02-28T23:45', [], [], 3],
['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45'])],
[('unsorted duplicate hours',
['2024-01-01T08:00', [17, 9, 17], [15], 4],
['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15']),
('product of two lists',
['2024-01-01T00:00', [9, 13], [0, 45], 5],
['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00']),
('dtstart after some slots',
['2024-01-02T12:00', [8, 12, 18], [0], 4],
['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00']),
('dtstart between minutes',
['2024-01-02T12:20', [12], [0, 20, 40], 4],
['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20']),
('three by three',
['2024-03-10T00:00', [6, 12, 18], [5, 10, 50], 7],
['2024-03-10T06:05',
'2024-03-10T06:10',
'2024-03-10T06:50',
'2024-03-10T12:05',
'2024-03-10T12:10',
'2024-03-10T12:50',
'2024-03-10T18:05']),
('count zero', ['2024-01-01T09:00', [9], [0], 0], []),
('no lists',
['2024-02-28T23:45', [], [], 3],
['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45'])],
[('dtstart after some slots',
['2024-01-02T12:00', [8, 12, 18], [0], 4],
['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00']),
('dtstart between minutes',
['2024-01-02T12:20', [12], [0, 20, 40], 4],
['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20']),
('three by three',
['2024-03-10T00:00', [6, 12, 18], [5, 10, 50], 7],
['2024-03-10T06:05',
'2024-03-10T06:10',
'2024-03-10T06:50',
'2024-03-10T12:05',
'2024-03-10T12:10',
'2024-03-10T12:50',
'2024-03-10T18:05']),
('count zero', ['2024-01-01T09:00', [9], [0], 0], []),
('no lists', ['2024-02-28T23:45', [], [], 3], ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45']),
('unsorted minutes',
['2024-02-28T07:00', [7, 8], [50, 10], 5],
['2024-02-28T07:10', '2024-02-28T07:50', '2024-02-28T08:10', '2024-02-28T08:50', '2024-02-29T07:10']),
('late hour only list',
['2024-05-05T22:15', [23, 1], [], 4],
['2024-05-05T23:15', '2024-05-06T01:15', '2024-05-06T23:15', '2024-05-07T01:15'])],
[('three by three',
['2024-03-10T00:00', [6, 12, 18], [5, 10, 50], 7],
['2024-03-10T06:05',
'2024-03-10T06:10',
'2024-03-10T06:50',
'2024-03-10T12:05',
'2024-03-10T12:10',
'2024-03-10T12:50',
'2024-03-10T18:05']),
('count zero', ['2024-01-01T09:00', [9], [0], 0], []),
('no lists', ['2024-02-28T23:45', [], [], 3], ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45']),
('unsorted minutes',
['2024-02-28T07:00', [7, 8], [50, 10], 5],
['2024-02-28T07:10', '2024-02-28T07:50', '2024-02-28T08:10', '2024-02-28T08:50', '2024-02-29T07:10']),
('late hour only list',
['2024-05-05T22:15', [23, 1], [], 4],
['2024-05-05T23:15', '2024-05-06T01:15', '2024-05-06T23:15', '2024-05-07T01:15']),
('regression: default minute from dtstart',
['2024-01-01T09:30', [9, 17], [], 4],
['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30']),
('only byminute',
['2024-01-01T14:10', [], [0, 30], 4],
['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00'])],
[('no lists', ['2024-02-28T23:45', [], [], 3], ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45']),
('unsorted minutes',
['2024-02-28T07:00', [7, 8], [50, 10], 5],
['2024-02-28T07:10', '2024-02-28T07:50', '2024-02-28T08:10', '2024-02-28T08:50', '2024-02-29T07:10']),
('late hour only list',
['2024-05-05T22:15', [23, 1], [], 4],
['2024-05-05T23:15', '2024-05-06T01:15', '2024-05-06T23:15', '2024-05-07T01:15']),
('regression: default minute from dtstart',
['2024-01-01T09:30', [9, 17], [], 4],
['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30']),
('only byminute',
['2024-01-01T14:10', [], [0, 30], 4],
['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00']),
('unsorted duplicate hours',
['2024-01-01T08:00', [17, 9, 17], [15], 4],
['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15']),
('product of two lists',
['2024-01-01T00:00', [9, 13], [0, 45], 5],
['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00'])]]
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: default minute from dtstart | ['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30'] | ['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30'] | Passed |
| only byminute | ['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00'] | ['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00'] | Passed |
| unsorted duplicate hours | ['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15'] | ['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15'] | Passed |
| product of two lists | ['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00'] | ['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00'] | Passed |
| dtstart after some slots | ['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00'] | ['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00'] | Passed |
| dtstart between minutes | ['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20'] | ['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20'] | Passed |
| three by three | ['2024-03-10T06:05', '2024-03-10T06:10', '2024-03-10T06:50', '2024-03-10T12:05', '2024-03-10T12:10', '2024-03-10T12:50', '2024-03-10T18:05'] | ['2024-03-10T06:05', '2024-03-10T06:10', '2024-03-10T06:50', '2024-03-10T12:05', '2024-03-10T12:10', '2024-03-10T12:50', '2024-03-10T18:05'] | Passed |
| no lists | ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45'] | ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45'] | Passed |
SHA-256 / 062425680d33fb733ed93f0420e998be958bc50b2fc1301d1ee36d3e01eb341d
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.334013+00:00.
Case digest / 523c3dbdfdddd175b07cb3c941ee9e376f01c6f3b9559a7711b73fdb631b57bc