/** * If the event is recurring, this function calculates the best * possible end date to use for the series. It will attempt to calculate * an end date from the RRULE if possible, and will fall back to the PHP * max date otherwise. The generateInstances function will still limit * the results regardless. For non-recurring events, it simply returns * the existing end date value as-is. */ function calculateEndDate($event) { global $date_format, $mappings; $end = $event[$mappings['end_date']]; $rrule = $event[$mappings['rrule']]; $isRecurring = isset($rrule) && $rrule !== ''; if ($isRecurring) { $max_date = new DateTime('9999-12-31'); $recurrence = new When(); $recurrence->rrule($rrule); if (isset($recurrence->end_date) && $recurrence->end_date < $max_date) { // The RRULE includes an explicit end date, so use that $end = $recurrence->end_date->format($date_format) . 'Z'; } else { if (isset($recurrence->count) && $recurrence->count > 0) { // The RRULE has a limit, so calculate the end date based on the instance count $count = 0; $newEnd; $rdates = $recurrence->recur($event[$mappings['start_date']])->rrule($rrule); while ($rdate = $rdates->next()) { $newEnd = $rdate; if (++$count > $recurrence->count) { break; } } // The 'minutes' portion should match Extensible.calendar.data.EventModel.resolution: $newEnd->modify('+' . $event[$mappings['duration']] . ' minutes'); $end = $newEnd->format($date_format) . 'Z'; } else { // The RRULE does not specify an end date or count, so default to max date $end = date($date_format, PHP_INT_MAX) . 'Z'; } } } return $end; }
/** * If the event is recurring, returns the maximum end date * supported by PHP so that the event will fall within future * query ranges as possibly having matching instances. Note * that in a real implementation it would be better to calculate * the actual recurrence pattern end date if possible. The current * recurrence class used in this example does not make it convenient * to do that, so for demo purposes we'll just use the PHP max date. * The generateInstances() method will still limit results based on * any end date specified, so it will work as expected -- it simply * means that in a real-world implementation querying might be slightly * less efficient (which does not apply in this example). */ private static function calculateEndDate($attr) { $end = $attr[Event::$end_date]; if (isset($attr[Event::$rrule]) && $attr[Event::$rrule] != '') { $max_date = new DateTime('9999-12-31'); $recurrence = new When(); $recurrence->rrule($attr[Event::$rrule]); if (isset($recurrence->end_date) && $recurrence->end_date < $max_date) { $end = $recurrence->end_date->format($_SESSION['dtformat']) . 'Z'; } else { if (isset($recurrence->count) && $recurrence->count > 0) { $count = 0; $newEnd; $rdates = $recurrence->recur($attr[Event::$start_date])->rrule($attr[Event::$rrule]); while ($rdate = $rdates->next()) { $newEnd = $rdate; if (++$count > $recurrence->count) { break; } } // The 'minutes' portion should match Extensible.calendar.data.EventModel.resolution: $newEnd->modify('+' . $attr[Event::$duration] . ' minutes'); $end = $newEnd->format($_SESSION['dtformat']) . 'Z'; } else { // default to max date if nothing else $end = date($_SESSION['dtformat'], PHP_INT_MAX) . 'Z'; } } } return $end; }