Fix: time-range filter matches VEVENT with whole-day DURATION

A calendar-query REPORT with a time-range filter failed to return a
VEVENT that has a whole-day DURATION (e.g. DURATION:P1D or P2D) whenever
the queried range fell inside the event but after DTSTART.

The VEVENT time-range logic in radicale/item/filter.py gated the
"non-zero duration" branch (rfc4791-9.9 line 2) on timedelta.seconds
instead of timedelta.total_seconds(). For a duration that is an exact
multiple of 24h, timedelta.seconds is 0 (the days component holds the
value), so the event was treated as zero-length (line 3) and only
matched a one-second window at its start. An identical event expressed
with DTEND matched correctly, confirming the defect is isolated to the
DURATION path.

Use total_seconds() so multi-day durations are handled correctly. Adds a
regression test (event11, DURATION:P2D) covering both an inside-range
match and an outside-range non-match.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
TowyTowy
2026-07-11 15:58:39 +02:00
parent 21ad7466c5
commit e557c0cd5e
5 changed files with 42 additions and 3 deletions

View File

@@ -402,8 +402,8 @@ def visit_time_ranges(vobject_item: vobject.base.Component, child_name: str,
return
elif duration is not None:
if original_duration is None:
original_duration = duration.seconds
if duration.seconds > 0:
original_duration = duration.total_seconds()
if duration.total_seconds() > 0:
# Line 2
if range_fn(dtstart, dtstart + duration,
is_recurrence):