diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9ac34598..3c6b0b37 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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
diff --git a/pyproject.toml b/pyproject.toml
index 20a94c9d..8db3b7ae 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -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"
diff --git a/radicale/item/filter.py b/radicale/item/filter.py
index 5f990075..46462487 100644
--- a/radicale/item/filter.py
+++ b/radicale/item/filter.py
@@ -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):
diff --git a/radicale/tests/static/event11.ics b/radicale/tests/static/event11.ics
new file mode 100644
index 00000000..47b00cb4
--- /dev/null
+++ b/radicale/tests/static/event11.ics
@@ -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
diff --git a/radicale/tests/test_base.py b/radicale/tests/test_base.py
index 3d80a259..381d6bed 100644
--- a/radicale/tests/test_base.py
+++ b/radicale/tests/test_base.py
@@ -1789,6 +1789,31 @@ permissions: RrWw""")
"""], 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(["""\
+
+
+
+
+"""], items=(11,))
+ assert "/calendar.ics/event11.ics" in answer
+ # Time-range fully after the event must not match.
+ answer = self._test_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(["""\