From 01c1cdac8b7dd810c41fc690a80a880f98afb790 Mon Sep 17 00:00:00 2001 From: PC Drew Date: Wed, 18 Apr 2018 11:25:05 -0600 Subject: [PATCH] Fixed bugs related to changes in the original event when recurring. Updated tests to work properly and to evaluate the actual events generated versus the recurrence dates. --- src/IcalParser.php | 37 ++-- tests/cal/daily_recur.ics | 16 -- tests/cal/daily_recur2.ics | 41 +++++ ...tances_with_modifications_to_first_day.ics | 16 +- tests/recurring_events.phpt | 163 +++++++++--------- 5 files changed, 153 insertions(+), 120 deletions(-) create mode 100755 tests/cal/daily_recur2.ics diff --git a/src/IcalParser.php b/src/IcalParser.php index 2d3be46..13eee68 100644 --- a/src/IcalParser.php +++ b/src/IcalParser.php @@ -549,25 +549,36 @@ public function getEvents() { $modifiedEventRecurID = $event['RECURRENCE-ID']; $modifiedEventSeq = intval($event['SEQUENCE'], 10); - if(!empty($this->data["_RECURRENCE_COUNTERS_BY_UID"][$modifiedEventUID])) { + if(isset($this->data["_RECURRENCE_COUNTERS_BY_UID"][$modifiedEventUID])) { $counter = $this->data[ "_RECURRENCE_COUNTERS_BY_UID" ][ $modifiedEventUID ]; $originalEvent = $this->data[ "VEVENT" ][ $counter ]; - if(!empty($originalEvent[ 'RECURRENCES' ]) && isset($originalEvent[ 'SEQUENCE' ])) { + if(isset($originalEvent[ 'SEQUENCE' ])) { $originalEventSeq = intval($originalEvent['SEQUENCE'], 10); - if($modifiedEventSeq > $originalEventSeq) { - for ($j = 0; $j < count($originalEvent['RECURRENCES']); $j++) { - $recurDate = $originalEvent[ 'RECURRENCES' ][$j]; - $formatedStartDate = $recurDate->format('Ymd\THis'); - if($formatedStartDate === $modifiedEventRecurID) { - unset($this->data[ "VEVENT" ][ $counter ]['RECURRENCES'][$j]); - $this->data["VEVENT"][$counter]['RECURRENCES'] = array_values($this->data["VEVENT"][$counter]['RECURRENCES']);break; + $originalEventFormattedStartDate = $originalEvent['DTSTART']->format('Ymd\THis'); + if ($modifiedEventRecurID === $originalEventFormattedStartDate && $modifiedEventSeq > $originalEventSeq) { + // this modifies the original event + $modifiedEvent = array_replace_recursive($originalEvent, $event); + $this->data[ "VEVENT" ][ $counter ] = $modifiedEvent; + foreach($events as $z => $event) { + if ($events[$z]['UID'] === $originalEvent['UID'] && + $events[$z]['SEQUENCE'] === $originalEvent['SEQUENCE']) { + // replace the original event with the modified event + $events[$z] = $modifiedEvent; + break; + } + } + $event = null; // don't add this to the $events[] array again + } else if (!empty($originalEvent[ 'RECURRENCES' ])) { + for($j = 0; $j < count($originalEvent[ 'RECURRENCES' ]); $j++) { + $recurDate = $originalEvent[ 'RECURRENCES' ][ $j ]; + $formattedStartDate = $recurDate->format('Ymd\THis'); + if($formattedStartDate === $modifiedEventRecurID) { + unset($this->data[ "VEVENT" ][ $counter ][ 'RECURRENCES' ][ $j ]); + $this->data[ "VEVENT" ][ $counter ][ 'RECURRENCES' ] = array_values($this->data[ "VEVENT" ][ $counter ][ 'RECURRENCES' ]); + break; } } - } else { - // don't save this event because the original, repeating event has a higher - // sequence number. This is extremely unlikely - $event = null; } } } diff --git a/tests/cal/daily_recur.ics b/tests/cal/daily_recur.ics index 6b3afbb..9983098 100755 --- a/tests/cal/daily_recur.ics +++ b/tests/cal/daily_recur.ics @@ -49,20 +49,4 @@ DESCRIPTION:This is an event reminder TRIGGER:-P0DT0H30M0S END:VALARM END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20170821 -DTEND;VALUE=DATE:20170822 -RRULE:FREQ=WEEKLY;UNTIL=20170911;BYDAY=MO -DTSTAMP:20170818T191547Z -UID:37mfdqtlcrrvbil9b3n7vicb1t@google.com -CLASS:PUBLIC -CREATED:20170818T175332Z -DESCRIPTION: -LAST-MODIFIED:20170818T175332Z -LOCATION: -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:Late Start\, SMS -TRANSP:TRANSPARENT -END:VEVENT END:VCALENDAR diff --git a/tests/cal/daily_recur2.ics b/tests/cal/daily_recur2.ics new file mode 100755 index 0000000..346f54e --- /dev/null +++ b/tests/cal/daily_recur2.ics @@ -0,0 +1,41 @@ +BEGIN:VCALENDAR +PRODID:-//Google Inc//Google Calendar 70.9054//EN +VERSION:2.0 +CALSCALE:GREGORIAN +X-WR-CALNAME:calmozilla1@gmail.com +X-WR-TIMEZONE:America/Los_Angeles +BEGIN:VTIMEZONE +TZID:America/Los_Angeles +X-LIC-LOCATION:America/Los_Angeles +BEGIN:DAYLIGHT +TZOFFSETFROM:-0800 +TZOFFSETTO:-0700 +TZNAME:PDT +DTSTART:19700308T020000 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:-0700 +TZOFFSETTO:-0800 +TZNAME:PST +DTSTART:19701101T020000 +RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +DTSTART;VALUE=DATE:20170821 +DTEND;VALUE=DATE:20170822 +RRULE:FREQ=WEEKLY;UNTIL=20170911;BYDAY=MO +DTSTAMP:20170818T191547Z +UID:37mfdqtlcrrvbil9b3n7vicb1t@google.com +CLASS:PUBLIC +CREATED:20170818T175332Z +DESCRIPTION: +LAST-MODIFIED:20170818T175332Z +LOCATION: +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:Late Start\, SMS +TRANSP:TRANSPARENT +END:VEVENT +END:VCALENDAR diff --git a/tests/cal/recur_instances_with_modifications_to_first_day.ics b/tests/cal/recur_instances_with_modifications_to_first_day.ics index e49a6ed..7dd2939 100755 --- a/tests/cal/recur_instances_with_modifications_to_first_day.ics +++ b/tests/cal/recur_instances_with_modifications_to_first_day.ics @@ -25,31 +25,31 @@ RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU END:STANDARD END:VTIMEZONE BEGIN:VEVENT -DTSTART;TZID=America/New_York:20160929T123000 -DTEND;TZID=America/New_York:20160929T160000 +DTSTART;TZID=America/New_York:20160915T123000 +DTEND;TZID=America/New_York:20160915T160000 +RRULE:FREQ=MONTHLY;UNTIL=20161020T035959Z;BYDAY=3TH DTSTAMP:20160913T221241Z UID:d28i2lkvhp2qb2v7n6oe9poikc@google.com -RECURRENCE-ID;TZID=America/New_York:20160915T123000 CREATED:20160705T193430Z DESCRIPTION:Professional Development for Staff LAST-MODIFIED:20160825T003008Z LOCATION: -SEQUENCE:2 +SEQUENCE:1 STATUS:CONFIRMED SUMMARY:Early Release for Students TRANSP:OPAQUE END:VEVENT BEGIN:VEVENT -DTSTART;TZID=America/New_York:20160915T123000 -DTEND;TZID=America/New_York:20160915T160000 -RRULE:FREQ=MONTHLY;UNTIL=20161020T035959Z;BYDAY=3TH +DTSTART;TZID=America/New_York:20160929T123000 +DTEND;TZID=America/New_York:20160929T160000 DTSTAMP:20160913T221241Z UID:d28i2lkvhp2qb2v7n6oe9poikc@google.com +RECURRENCE-ID;TZID=America/New_York:20160915T123000 CREATED:20160705T193430Z DESCRIPTION:Professional Development for Staff LAST-MODIFIED:20160825T003008Z LOCATION: -SEQUENCE:1 +SEQUENCE:2 STATUS:CONFIRMED SUMMARY:Early Release for Students TRANSP:OPAQUE diff --git a/tests/recurring_events.phpt b/tests/recurring_events.phpt index ab01339..07fa0b5 100644 --- a/tests/recurring_events.phpt +++ b/tests/recurring_events.phpt @@ -15,33 +15,25 @@ $cal = new \om\IcalParser(); $results = $cal->parseFile(__DIR__ . '/cal/recur_instances_finite.ics'); $events = $cal->getSortedEvents(); -Assert::false(empty($events[0]['RECURRENCES'])); - // DTSTART;TZID=America/Los_Angeles:20121002T100000 // DTEND;TZID=America/Los_Angeles:20121002T103000 // RRULE:FREQ=MONTHLY;INTERVAL=1;BYDAY=1TU;UNTIL=20121231T100000 // RDATE;TZID=America/Los_Angeles:20121110T100000 // RDATE;TZID=America/Los_Angeles:20121105T100000 -$recurrences = $events[0]['RECURRENCES']; -Assert::equal(5, sizeof($recurrences)); -Assert::equal($events[0]['DTSTART'], $recurrences[0]); -Assert::equal('5.11.2012 10:00:00', $recurrences[1]->format('j.n.Y H:i:s')); -Assert::equal('6.11.2012 10:00:00', $recurrences[2]->format('j.n.Y H:i:s')); -Assert::equal('10.11.2012 10:00:00', $recurrences[3]->format('j.n.Y H:i:s')); -Assert::equal('4.12.2012 10:00:00', $recurrences[4]->format('j.n.Y H:i:s')); - -$eventsWithRecurring = $cal->getSortedEvents(true); -Assert::equal(5, sizeof($eventsWithRecurring)); -Assert::equal($eventsWithRecurring[0]['DTSTART'], $recurrences[0]); -Assert::equal($eventsWithRecurring[1]['DTSTART'], $recurrences[1]); -Assert::equal($eventsWithRecurring[2]['DTSTART'], $recurrences[2]); -Assert::equal($eventsWithRecurring[3]['DTSTART'], $recurrences[3]); -Assert::equal($eventsWithRecurring[4]['DTSTART'], $recurrences[4]); +Assert::equal(5, sizeof($events)); +Assert::equal('2.10.2012 10:00:00', $events[0]['DTSTART']->format('j.n.Y H:i:s')); +Assert::equal('5.11.2012 10:00:00', $events[1]['DTSTART']->format('j.n.Y H:i:s')); +Assert::equal('6.11.2012 10:00:00', $events[2]['DTSTART']->format('j.n.Y H:i:s')); +Assert::equal('10.11.2012 10:00:00', $events[3]['DTSTART']->format('j.n.Y H:i:s')); +Assert::equal('4.12.2012 10:00:00', $events[4]['DTSTART']->format('j.n.Y H:i:s')); $results = $cal->parseFile(__DIR__ . '/cal/recur_instances.ics'); $events = $cal->getSortedEvents(); -Assert::false(empty($events[0]['RECURRENCES'])); +$recurrences = []; +foreach($events as $i => $event) { + $recurrences[] = $event['DTSTART']; +} // DTSTART;TZID=America/Los_Angeles:20121002T100000 // DTEND;TZID=America/Los_Angeles:20121002T103000 @@ -53,42 +45,42 @@ Assert::false(empty($events[0]['RECURRENCES'])); // EXDATE;TZID=America/Los_Angeles:20130205T100000 // total = 36 events - 3 exclusions + 3 additions // because there is no "UNTIL", we only calculate the next 3 years of repeating events -$recurrences = $events[0]['RECURRENCES']; -Assert::equal(34, sizeof($recurrences)); -Assert::equal('06.11.2012 10:00:00', $recurrences[0]->format('d.m.Y H:i:s')); -Assert::equal('10.11.2012 10:00:00', $recurrences[1]->format('d.m.Y H:i:s')); -Assert::equal('30.11.2012 10:00:00', $recurrences[2]->format('d.m.Y H:i:s')); -Assert::equal('01.01.2013 10:00:00', $recurrences[3]->format('d.m.Y H:i:s')); -Assert::equal('05.03.2013 10:00:00', $recurrences[4]->format('d.m.Y H:i:s')); -Assert::equal('07.05.2013 10:00:00', $recurrences[5]->format('d.m.Y H:i:s')); -Assert::equal('04.06.2013 10:00:00', $recurrences[6]->format('d.m.Y H:i:s')); -Assert::equal('02.07.2013 10:00:00', $recurrences[7]->format('d.m.Y H:i:s')); -Assert::equal('06.08.2013 10:00:00', $recurrences[8]->format('d.m.Y H:i:s')); -Assert::equal('03.09.2013 10:00:00', $recurrences[9]->format('d.m.Y H:i:s')); -Assert::equal('01.10.2013 10:00:00', $recurrences[10]->format('d.m.Y H:i:s')); -Assert::equal('05.11.2013 10:00:00', $recurrences[11]->format('d.m.Y H:i:s')); -Assert::equal('03.12.2013 10:00:00', $recurrences[12]->format('d.m.Y H:i:s')); -Assert::equal('07.01.2014 10:00:00', $recurrences[13]->format('d.m.Y H:i:s')); -Assert::equal('04.02.2014 10:00:00', $recurrences[14]->format('d.m.Y H:i:s')); -Assert::equal('04.03.2014 10:00:00', $recurrences[15]->format('d.m.Y H:i:s')); -Assert::equal('01.04.2014 10:00:00', $recurrences[16]->format('d.m.Y H:i:s')); -Assert::equal('06.05.2014 10:00:00', $recurrences[17]->format('d.m.Y H:i:s')); -Assert::equal('03.06.2014 10:00:00', $recurrences[18]->format('d.m.Y H:i:s')); -Assert::equal('01.07.2014 10:00:00', $recurrences[19]->format('d.m.Y H:i:s')); -Assert::equal('05.08.2014 10:00:00', $recurrences[20]->format('d.m.Y H:i:s')); -Assert::equal('02.09.2014 10:00:00', $recurrences[21]->format('d.m.Y H:i:s')); -Assert::equal('07.10.2014 10:00:00', $recurrences[22]->format('d.m.Y H:i:s')); -Assert::equal('04.11.2014 10:00:00', $recurrences[23]->format('d.m.Y H:i:s')); -Assert::equal('02.12.2014 10:00:00', $recurrences[24]->format('d.m.Y H:i:s')); -Assert::equal('06.01.2015 10:00:00', $recurrences[25]->format('d.m.Y H:i:s')); -Assert::equal('03.02.2015 10:00:00', $recurrences[26]->format('d.m.Y H:i:s')); -Assert::equal('03.03.2015 10:00:00', $recurrences[27]->format('d.m.Y H:i:s')); -Assert::equal('07.04.2015 10:00:00', $recurrences[28]->format('d.m.Y H:i:s')); -Assert::equal('05.05.2015 10:00:00', $recurrences[29]->format('d.m.Y H:i:s')); -Assert::equal('02.06.2015 10:00:00', $recurrences[30]->format('d.m.Y H:i:s')); -Assert::equal('07.07.2015 10:00:00', $recurrences[31]->format('d.m.Y H:i:s')); -Assert::equal('04.08.2015 10:00:00', $recurrences[32]->format('d.m.Y H:i:s')); -Assert::equal('01.09.2015 10:00:00', $recurrences[33]->format('d.m.Y H:i:s')); +Assert::equal(35, sizeof($recurrences)); +Assert::equal('02.10.2012 15:00:00', $recurrences[0]->format('d.m.Y H:i:s')); +Assert::equal('06.11.2012 20:00:00', $recurrences[1]->format('d.m.Y H:i:s')); +Assert::equal('10.11.2012 10:00:00', $recurrences[2]->format('d.m.Y H:i:s')); +Assert::equal('30.11.2012 10:00:00', $recurrences[3]->format('d.m.Y H:i:s')); +Assert::equal('01.01.2013 10:00:00', $recurrences[4]->format('d.m.Y H:i:s')); +Assert::equal('05.03.2013 10:00:00', $recurrences[5]->format('d.m.Y H:i:s')); +Assert::equal('07.05.2013 10:00:00', $recurrences[6]->format('d.m.Y H:i:s')); +Assert::equal('04.06.2013 10:00:00', $recurrences[7]->format('d.m.Y H:i:s')); +Assert::equal('02.07.2013 10:00:00', $recurrences[8]->format('d.m.Y H:i:s')); +Assert::equal('06.08.2013 10:00:00', $recurrences[9]->format('d.m.Y H:i:s')); +Assert::equal('03.09.2013 10:00:00', $recurrences[10]->format('d.m.Y H:i:s')); +Assert::equal('01.10.2013 10:00:00', $recurrences[11]->format('d.m.Y H:i:s')); +Assert::equal('05.11.2013 10:00:00', $recurrences[12]->format('d.m.Y H:i:s')); +Assert::equal('03.12.2013 10:00:00', $recurrences[13]->format('d.m.Y H:i:s')); +Assert::equal('07.01.2014 10:00:00', $recurrences[14]->format('d.m.Y H:i:s')); +Assert::equal('04.02.2014 10:00:00', $recurrences[15]->format('d.m.Y H:i:s')); +Assert::equal('04.03.2014 10:00:00', $recurrences[16]->format('d.m.Y H:i:s')); +Assert::equal('01.04.2014 10:00:00', $recurrences[17]->format('d.m.Y H:i:s')); +Assert::equal('06.05.2014 10:00:00', $recurrences[18]->format('d.m.Y H:i:s')); +Assert::equal('03.06.2014 10:00:00', $recurrences[19]->format('d.m.Y H:i:s')); +Assert::equal('01.07.2014 10:00:00', $recurrences[20]->format('d.m.Y H:i:s')); +Assert::equal('05.08.2014 10:00:00', $recurrences[21]->format('d.m.Y H:i:s')); +Assert::equal('02.09.2014 10:00:00', $recurrences[22]->format('d.m.Y H:i:s')); +Assert::equal('07.10.2014 10:00:00', $recurrences[23]->format('d.m.Y H:i:s')); +Assert::equal('04.11.2014 10:00:00', $recurrences[24]->format('d.m.Y H:i:s')); +Assert::equal('02.12.2014 10:00:00', $recurrences[25]->format('d.m.Y H:i:s')); +Assert::equal('06.01.2015 10:00:00', $recurrences[26]->format('d.m.Y H:i:s')); +Assert::equal('03.02.2015 10:00:00', $recurrences[27]->format('d.m.Y H:i:s')); +Assert::equal('03.03.2015 10:00:00', $recurrences[28]->format('d.m.Y H:i:s')); +Assert::equal('07.04.2015 10:00:00', $recurrences[29]->format('d.m.Y H:i:s')); +Assert::equal('05.05.2015 10:00:00', $recurrences[30]->format('d.m.Y H:i:s')); +Assert::equal('02.06.2015 10:00:00', $recurrences[31]->format('d.m.Y H:i:s')); +Assert::equal('07.07.2015 10:00:00', $recurrences[32]->format('d.m.Y H:i:s')); +Assert::equal('04.08.2015 10:00:00', $recurrences[33]->format('d.m.Y H:i:s')); +Assert::equal('01.09.2015 10:00:00', $recurrences[34]->format('d.m.Y H:i:s')); foreach ($events[0]['EXDATES'] as $exDate) { Assert::notContains($exDate, $recurrences); @@ -116,42 +108,42 @@ $results = $cal->parseFile(__DIR__ . '/cal/recur_instances_with_modifications_an // Build the cache of RECURRENCE-IDs and EXDATES first, so that we can properly determine the interval $eventCache = array(); foreach($results['VEVENT'] as $event) { - $eventSequence = empty($event['SEQUENCE']) ? "0" : $event['SEQUENCE']; - $eventRecurrenceID = empty($event['RECURRENCE-ID']) ? "0" : $event['RECURRENCE-ID']; + $eventSequence = empty($event['SEQUENCE']) ? "0" : $event['SEQUENCE']; + $eventRecurrenceID = empty($event['RECURRENCE-ID']) ? "0" : $event['RECURRENCE-ID']; - $eventCache[$event['UID']][$eventRecurrenceID][$eventSequence] = $event; + $eventCache[$event['UID']][$eventRecurrenceID][$eventSequence] = $event; } $trueEvents = array(); foreach($results['VEVENT'] as $event) { - if(empty($event['RECURRENCES'])) { - $trueEvents[] = $event; - } else { - $eventUID = $event['UID']; - foreach($event['RECURRENCES'] as $recurrence) { - $eventRecurrenceID = $recurrence->format("Ymd"); - if(empty($eventCache[$eventUID][$eventRecurrenceID])) { - $trueEvents[$eventRecurrenceID] = array('DTSTART' => $recurrence); - } else { - krsort($eventCache[$eventUID][$eventRecurrenceID]); - $keys = array_keys($eventCache[$eventUID][$eventRecurrenceID]); - $trueEvents[$eventRecurrenceID] = $eventCache[$eventUID][$eventRecurrenceID][$keys[0]]; - } - } - } + if(empty($event['RECURRENCES'])) { + $trueEvents[] = $event; + } else { + $eventUID = $event['UID']; + foreach($event['RECURRENCES'] as $recurrence) { + $eventRecurrenceID = $recurrence->format("Ymd"); + if(empty($eventCache[$eventUID][$eventRecurrenceID])) { + $trueEvents[$eventRecurrenceID] = array('DTSTART' => $recurrence); + } else { + krsort($eventCache[$eventUID][$eventRecurrenceID]); + $keys = array_keys($eventCache[$eventUID][$eventRecurrenceID]); + $trueEvents[$eventRecurrenceID] = $eventCache[$eventUID][$eventRecurrenceID][$keys[0]]; + } + } + } } usort($trueEvents, function ($a, $b) { - return $a['DTSTART'] > $b['DTSTART']; + return $a['DTSTART'] > $b['DTSTART']; }); $events = $cal->getSortedEvents(true); Assert::false(empty($events[0]['RECURRENCES'])); Assert::equal(count($trueEvents), count($events)); foreach($trueEvents as $index => $trueEvent) { - Assert::equal($trueEvent['DTSTART']->format("Ymd"), $events[$index]['DTSTART']->format("Ymd")); + Assert::equal($trueEvent['DTSTART']->format("Ymd"), $events[$index]['DTSTART']->format("Ymd")); } -/* + // There is still an issue that needs to be resolved when modifications are made to the initial event that is the // base of the recurrences. The below ICS file has a great edge case example: one event, no recurrences in the // recurring ruleset, and a modification to the initial event. @@ -160,15 +152,20 @@ $events = $cal->getSortedEvents(); Assert::true(empty($events[0]['RECURRENCES'])); // edited event Assert::true(empty($events[1]['RECURRENCES'])); // recurring event base with no recurrences Assert::equal(1, count($events)); -*/ $results = $cal->parseFile(__DIR__ . '/cal/daily_recur.ics'); $events = $cal->getSortedEvents(); +print("num events: " . count($events) . "\n"); +$period = new DatePeriod(new DateTime('20120801T050000'), new DateInterval('P1D'), 365 * 3); +foreach($period as $i => $day) { + Assert::equal($day->format('j.n.Y H:i:s'), $events[$i]['DTSTART']->format('j.n.Y H:i:s')); +} + +$results = $cal->parseFile(__DIR__ . '/cal/daily_recur2.ics'); +$events = $cal->getSortedEvents(); -Assert::false(empty($events[1]['RECURRENCES'])); -$recurrences = $events[1]['RECURRENCES']; -Assert::equal(4, sizeof($recurrences)); -Assert::equal($events[1]['DTSTART'], $recurrences[0]); -Assert::equal('28.8.2017 00:00:00', $recurrences[1]->format('j.n.Y H:i:s')); -Assert::equal('4.9.2017 00:00:00', $recurrences[2]->format('j.n.Y H:i:s')); -Assert::equal('11.9.2017 00:00:00', $recurrences[3]->format('j.n.Y H:i:s')); \ No newline at end of file +Assert::equal(4, sizeof($events)); +Assert::equal('21.8.2017 00:00:00', $events[0]['DTSTART']->format('j.n.Y H:i:s')); +Assert::equal('28.8.2017 00:00:00', $events[1]['DTSTART']->format('j.n.Y H:i:s')); +Assert::equal('4.9.2017 00:00:00', $events[2]['DTSTART']->format('j.n.Y H:i:s')); +Assert::equal('11.9.2017 00:00:00', $events[3]['DTSTART']->format('j.n.Y H:i:s')); \ No newline at end of file