Merge pull request #2178 from TowyTowy/fix/time-range-whole-day-duration

Fix: time-range filter matches VEVENT with whole-day DURATION
This commit is contained in:
Peter Bieringer
2026-07-12 08:30:59 +03:00
committed by GitHub
5 changed files with 42 additions and 3 deletions

View File

@@ -1,5 +1,8 @@
# Changelog
## 3.7.7.dev
* Fix: time-range filter treated a VEVENT with a whole-day DURATION (e.g. P1D, P2D) as zero-length (timedelta.seconds instead of total_seconds), so such events were missing from calendar-query REPORT results
## 3.7.6
* Extension: item verification on commandline
* Improvement: catch lack of support of PERIOD in vobject <= 0.9.9

View File

@@ -3,7 +3,7 @@ name = "Radicale"
# When the version is updated, a new section in the CHANGELOG.md file must be
# added too.
readme = "README.md"
version = "3.7.6"
version = "3.7.7.dev"
authors = [{name = "Guillaume Ayoub", email = "guillaume.ayoub@kozea.fr"}, {name = "Unrud", email = "unrud@outlook.com"}, {name = "Peter Bieringer", email = "pb@bieringer.de"}]
license = {text = "GNU GPL v3"}
description = "CalDAV and CardDAV Server"

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):

View File

@@ -0,0 +1,11 @@
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Radicale//NONSGML Radicale Server//EN
BEGIN:VEVENT
DTSTAMP:20130901T000000Z
UID:event11
SUMMARY:event11
DTSTART:20130901T000000Z
DURATION:P2D
END:VEVENT
END:VCALENDAR

View File

@@ -1789,6 +1789,31 @@ permissions: RrWw""")
</C:comp-filter>"""], items=(9,))
assert "/calendar.ics/event9.ics" not in answer
def test_time_range_filter_events_whole_day_duration(self) -> None:
"""Report time-range filter on an event with a whole-day DURATION.
event11 starts 2013-09-01T00:00:00Z and lasts DURATION:P2D, i.e. it is
ongoing until 2013-09-03T00:00:00Z. A time-range that falls inside the
span (but after DTSTART) must match it, exactly as it would for an
equivalent event expressed with DTEND.
"""
# Time-range fully inside the 2-day event, after DTSTART.
answer = self._test_filter(["""\
<C:comp-filter name="VCALENDAR">
<C:comp-filter name="VEVENT">
<C:time-range start="20130902T000000Z" end="20130902T120000Z"/>
</C:comp-filter>
</C:comp-filter>"""], items=(11,))
assert "/calendar.ics/event11.ics" in answer
# Time-range fully after the event must not match.
answer = self._test_filter(["""\
<C:comp-filter name="VCALENDAR">
<C:comp-filter name="VEVENT">
<C:time-range start="20130904T000000Z" end="20130905T000000Z"/>
</C:comp-filter>
</C:comp-filter>"""], items=(11,))
assert "/calendar.ics/event11.ics" not in answer
def test_time_range_filter_without_comp_filter(self) -> None:
"""Report request with time-range filter without comp-filter on events."""
answer = self._test_filter(["""\