diff --git a/ReleaseNotes.txt b/ReleaseNotes.txt index 6f1e5a91e..03a820695 100644 --- a/ReleaseNotes.txt +++ b/ReleaseNotes.txt @@ -9,6 +9,7 @@ Version 3.0.19 (UNRELEASED): * Improved libicu discrovery on Mac with homebrew * Properly set DYLD_LIBRARY_PATH on Mac for libical-ical tests * Resolved known limitation: Negative values are now also supported for `BYMONTHDAY` and `BYYEARDAY`. + * Add support for RDATE;VALUE=PERIOD * Fix time conversion to time_t for times before epoch Version 3.0.18 (31 March 2024): diff --git a/src/libical/icalcomponent.c b/src/libical/icalcomponent.c index 2c67dded9..ce9ec360e 100644 --- a/src/libical/icalcomponent.c +++ b/src/libical/icalcomponent.c @@ -905,27 +905,40 @@ void icalcomponent_foreach_recurrence(icalcomponent *comp, struct icaldatetimeperiodtype rdate_period = icalproperty_get_rdate(rdate); + struct icaltimetype rdate_start = rdate_period.time; + time_t rdate_duration = 0; /* RDATES can specify raw datetimes, periods, or dates. - we only support raw datetimes for now.. + we only support raw datetimes and periods for now. @todo Add support for other types */ - if (icaltime_is_null_time(rdate_period.time)) - continue; + if (icaltime_is_null_time(rdate_start)) { + rdate_start = rdate_period.period.start; + + if (icaltime_is_null_time(rdate_period.period.end)) { + rdate_duration = + (time_t)icaldurationtype_as_int(rdate_period.period.duration); + } else { + recurspan.end = + icaltime_as_timet_with_zone(rdate_period.period.end, + rdate_period.time.zone ? rdate_period.time.zone : icaltimezone_get_utc_timezone()); + } + } else { + rdate_duration = dtduration; + } recurspan.start = - icaltime_as_timet_with_zone(rdate_period.time, - rdate_period.time.zone ? - rdate_period.time.zone : - icaltimezone_get_utc_timezone()); - recurspan.end = recurspan.start + dtduration; + icaltime_as_timet_with_zone(rdate_start, + rdate_period.time.zone ? rdate_period.time.zone : icaltimezone_get_utc_timezone()); + if (rdate_duration) + recurspan.end = recurspan.start + rdate_duration; /* save the iterator ICK! */ property_iterator = comp->property_iterator; if (!icalproperty_recurrence_is_excluded(comp, - &dtstart, &rdate_period.time)) { + &dtstart, &rdate_start)) { /* call callback action */ if (icaltime_span_overlaps(&recurspan, &limit_span)) (*callback) (comp, &recurspan, callback_data); diff --git a/src/test/regression.c b/src/test/regression.c index 6178469ff..71c6822c3 100644 --- a/src/test/regression.c +++ b/src/test/regression.c @@ -683,6 +683,29 @@ void test_component_foreach(void) icalcomponent_free(calendar); + calStr = + "BEGIN:VCALENDAR\n" + "BEGIN:VEVENT\n" + "DTSTART;20180220T020000Z\n" + "DURATION:PT4H\n" + "RDATE;20180221T020000Z,20180222T020000Z\n" + "RDATE;VALUE=PERIOD:20180223T020000Z/20180223T030000Z,\n" + " 20180224T020000Z/PT2H\n" + "END:VEVENT\n" + "END:VCALENDAR\n"; + + calendar = icalparser_parse_string(calStr); + event = icalcomponent_get_first_component(calendar, ICAL_VEVENT_COMPONENT); + + t_start = icaltime_from_string("20180219T000000Z"); + t_end = icaltime_from_string("20180225T000000Z"); + + foundExpectedCnt = 0; + icalcomponent_foreach_recurrence(event, t_start, t_end, test_component_foreach_callback, &foundExpectedCnt); + ok("Exactly five instances were returned for an event with RDATEs.", foundExpectedCnt == 5); + + icalcomponent_free(calendar); + for (i = 0; i < 3; i++) { /* Add one week with every run, so the first run will address the