Skip to content

Commit

Permalink
icalcomponent_foreach_recurrence(): add support for RDATE;VALUE=PERIOD
Browse files Browse the repository at this point in the history
  • Loading branch information
ksmurchison authored and winterz committed Nov 18, 2024
1 parent 9274e56 commit 0f5c4b2
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 9 deletions.
1 change: 1 addition & 0 deletions ReleaseNotes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
31 changes: 22 additions & 9 deletions src/libical/icalcomponent.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
23 changes: 23 additions & 0 deletions src/test/regression.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 0f5c4b2

Please sign in to comment.