public static function addEvents(&$results, &$event, $startDate, $endDate, $showRecurrence, $json, $coverDates = true)
{
/* If the event has a custom timezone, we need to convert the
* recurrence object to the event's timezone while calculating next
* recurrences, to take DST changes in both the event's and the local
* timezone into account. */
$convert = $event->timezone && $event->getDriver()->supportsTimezones();
if ($convert) {
$timezone = date_default_timezone_get();
}
// If we are adding coverDates, but have no $endDate, default to
// +5 years from $startDate. This protects against hitting memory
// limit and other issues due to extremely long loops if a single event
// was added with a duration of thousands of years while still
// providing for reasonable alarm trigger times.
if ($coverDates && empty($endDate)) {
$endDate = clone $startDate;
$endDate->year += 5;
}
if ($event->recurs() && $showRecurrence) {
/* Recurring Event. */
/* If the event ends at 12am and does not end at the same time
* that it starts (0 duration), set the end date to the previous
* day's end date. */
if ($event->end->hour == 0 && $event->end->min == 0 && $event->end->sec == 0 && $event->start->compareDateTime($event->end) != 0) {
$event->end = new Horde_Date(array('hour' => 23, 'min' => 59, 'sec' => 59, 'month' => $event->end->month, 'mday' => $event->end->mday - 1, 'year' => $event->end->year));
}
/* We can't use the event duration here because we might cover a
* daylight saving time switch. */
$diff = array($event->end->year - $event->start->year, $event->end->month - $event->start->month, $event->end->mday - $event->start->mday, $event->end->hour - $event->start->hour, $event->end->min - $event->start->min);
if ($event->start->compareDateTime($startDate) < 0) {
/* The first time the event happens was before the period
* started. Start searching for recurrences from the start of
* the period. */
$next = new Horde_Date(array('year' => $startDate->year, 'month' => $startDate->month, 'mday' => $startDate->mday), $event->timezone);
} else {
/* The first time the event happens is in the range; unless
* there is an exception for this ocurrence, add it. */
if (!$event->recurrence->hasException($event->start->year, $event->start->month, $event->start->mday)) {
if ($coverDates) {
self::addCoverDates($results, $event, $event->start, $event->end, $json, null, null, $endDate);
} else {
$results[$event->start->dateString()][$event->id] = $json ? $event->toJson() : $event;
}
}
/* Start searching for recurrences from the day after it
* starts. */
$next = clone $event->start;
++$next->mday;
}
if ($convert) {
$event->recurrence->start->setTimezone($event->timezone);
if ($event->recurrence->hasRecurEnd()) {
$event->recurrence->recurEnd->setTimezone($event->timezone);
}
}
/* Add all recurrences of the event. */
$next = $event->recurrence->nextRecurrence($next);
if ($next && $convert) {
/* Resetting after the nextRecurrence() call, because
* we need to test if the next recurrence in the
* event's timezone actually matches the interval we
* check in the local timezone. This is done on each
* nextRecurrence() further below. */
$next->setTimezone($timezone);
}
while ($next !== false && $next->compareDate($endDate) <= 0) {
if (!$event->recurrence->hasException($next->year, $next->month, $next->mday)) {
/* Add the event to all the days it covers. */
$nextEnd = clone $next;
$nextEnd->year += $diff[0];
$nextEnd->month += $diff[1];
$nextEnd->mday += $diff[2];
$nextEnd->hour += $diff[3];
$nextEnd->min += $diff[4];
$addEvent = clone $event;
$addEvent->start = $addEvent->originalStart = $next;
$addEvent->end = $addEvent->originalEnd = $nextEnd;
if ($coverDates) {
self::addCoverDates($results, $addEvent, $next, $nextEnd, $json, null, null, $endDate);
} else {
$addEvent->start = $next;
$addEvent->end = $nextEnd;
$results[$addEvent->start->dateString()][$addEvent->id] = $json ? $addEvent->toJson() : $addEvent;
}
}
if ($convert) {
$next->setTimezone($event->timezone);
}
$next = $event->recurrence->nextRecurrence(array('year' => $next->year, 'month' => $next->month, 'mday' => $next->mday + 1, 'hour' => $next->hour, 'min' => $next->min, 'sec' => $next->sec));
if ($next && $convert) {
$next->setTimezone($timezone);
}
}
} else {
/* Event only occurs once. */
if (!$coverDates) {
$results[$event->start->dateString()][$event->id] = $json ? $event->toJson() : $event;
} else {
$allDay = $event->isAllDay();
/* Work out what day it starts on. */
if ($startDate && $event->start->compareDateTime($startDate) < 0) {
/* It started before the beginning of the period. */
if ($event->recurs()) {
$eventStart = $event->recurrence->nextRecurrence($startDate);
$originalStart = clone $eventStart;
} else {
$eventStart = clone $startDate;
$originalStart = clone $event->start;
}
} else {
$eventStart = clone $event->start;
$originalStart = clone $event->start;
}
/* Work out what day it ends on. */
if ($endDate && $event->end->compareDateTime($endDate) > 0) {
/* Ends after the end of the period. */
if (is_object($endDate)) {
$eventEnd = clone $endDate;
$originalEnd = clone $event->end;
} else {
$eventEnd = $endDate;
$originalEnd = new Horde_Date($endDate);
}
} else {
/* Need to perform some magic if this is a single instance
* of a recurring event since $event->end would be the
* original end date, not the recurrence's end date. */
if ($event->recurs()) {
$diff = array($event->end->year - $event->start->year, $event->end->month - $event->start->month, $event->end->mday - $event->start->mday, $event->end->hour - $event->start->hour, $event->end->min - $event->start->min);
$theEnd = $event->recurrence->nextRecurrence($eventStart);
$theEnd->year += $diff[0];
$theEnd->month += $diff[1];
$theEnd->mday += $diff[2];
$theEnd->hour += $diff[3];
$theEnd->min += $diff[4];
if ($convert) {
$eventStart->setTimezone($timezone);
$theEnd->setTimezone($timezone);
}
} else {
$theEnd = clone $event->end;
}
$originalEnd = clone $theEnd;
/* If the event doesn't end at 12am set the end date to
* the current end date. If it ends at 12am and does not
* end at the same time that it starts (0 duration), set
* the end date to the previous day's end date. */
if ($theEnd->hour != 0 || $theEnd->min != 0 || $theEnd->sec != 0 || $event->start->compareDateTime($theEnd) == 0 || $allDay) {
$eventEnd = clone $theEnd;
} else {
$eventEnd = new Horde_Date(array('hour' => 23, 'min' => 59, 'sec' => 59, 'month' => $theEnd->month, 'mday' => $theEnd->mday - 1, 'year' => $theEnd->year));
}
}
self::addCoverDates($results, $event, $eventStart, $eventEnd, $json, $originalStart, $originalEnd, $endDate);
}
}
ksort($results);
}