Search code examples
icalendarsabrecaldavsabredav

Caldav not returning event within time-range query


I have an iCalendar event in my Sabre:

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CalDAV Client//EN
BEGIN:VEVENT
UID:5e44cec8-33ed-4f24-82c7-f33483afa50d
DTSTART:20200805T080000Z
SUMMARY:summary
STATUS:CONFIRMED
TRANSP:OPAQUE
DURATION:PT30M
CATEGORIES:RESERVATION
DTSTAMP:20200716T211928Z
END:VEVENT
END:VCALENDAR

It starts at '2020-08-05T08:00:00.000Z' and with duration of 30 minutes, ends at '2020-08-05T08:30:00.000Z'.

If I submit the following query:

<c:calendar-query xmlns:c="urn:ietf:params:xml:ns:caldav"
    xmlns:cs="http://calendarserver.org/ns/"
    xmlns:ca="http://apple.com/ns/ical/"
    xmlns:d="DAV:">
    <d:prop>
        <c:calendar-data />
    </d:prop>
    <c:filter>
        <c:comp-filter name="VCALENDAR">
            <c:comp-filter name="VEVENT">
                <c:time-range start="20200805T080000Z" end="20200805T180000Z"/>
            </c:comp-filter>
        </c:comp-filter>
    </c:filter>
    <c:timezone>GMT</c:timezone>
</c:calendar-query>

The mentioned event gets returned. However if I move the start=... even just by one second, like so start="20200805T080001Z" it does not get returned.

According to section 9.9 or Caldav RFC 4791, it should be returned. Condition from the mentioned section:

(start <  DTSTART+DURATION AND end > DTSTART) 

Solution

  • I figured it out, I'm using Mongo Backend instead of Sabre's PDO Backend and the mentioned Mongo Backend has an error that the PDO one doesn't.

    Piece of code causing the error:

    $endDate = clone $component->DTSTART->getDateTime();
    $endDate->add(VObject\DateTimeParser::parse($component->DURATION->getValue()));
    $lastOccurence = $endDate->getTimeStamp();
    

    endDate is an Immutable Date and therefore endDate needs to be reassigned for the add function to take any effect.

    Fixed code:

    $endDate = clone $component->DTSTART->getDateTime();
    $endDate = $endDate->add(VObject\DateTimeParser::parse($component->DURATION->getValue()));
    $lastOccurence = $endDate->getTimeStamp();
    

    You can also see this correctly implemented on the github page of the PDO Backend here.