/** * Obtain a recurrence object. Note this returns a Horde_Date_Recurrence * object, not Horde_ActiveSync_Message_Recurrence. * * @return Horde_Date_Recurrence */ public function getRecurrence() { if (!($recurrence = $this->_getAttribute('recurrence'))) { return false; } $d = clone $this->_getAttribute('starttime'); $d->setTimezone($this->getTimezone()); $rrule = new Horde_Date_Recurrence($d); /* Map MS AS type field to Horde_Date_Recurrence types */ switch ($recurrence->type) { case Horde_ActiveSync_Message_Recurrence::TYPE_DAILY: $rrule->setRecurType(Horde_Date_Recurrence::RECUR_DAILY); break; case Horde_ActiveSync_Message_Recurrence::TYPE_WEEKLY: $rrule->setRecurType(Horde_Date_Recurrence::RECUR_WEEKLY); $rrule->setRecurOnDay($recurrence->dayofweek); break; case Horde_ActiveSync_Message_Recurrence::TYPE_MONTHLY: $rrule->setRecurType(Horde_Date_Recurrence::RECUR_MONTHLY_DATE); break; case Horde_ActiveSync_Message_Recurrence::TYPE_MONTHLY_NTH: $rrule->setRecurType(Horde_Date_Recurrence::RECUR_MONTHLY_WEEKDAY); $rrule->setRecurOnDay($recurrence->dayofweek); break; case Horde_ActiveSync_Message_Recurrence::TYPE_YEARLY: $rrule->setRecurType(Horde_Date_Recurrence::RECUR_YEARLY_DATE); break; case Horde_ActiveSync_Message_Recurrence::TYPE_YEARLYNTH: $rrule->setRecurType(Horde_Date_Recurrence::RECUR_YEARLY_WEEKDAY); $rrule->setRecurOnDay($recurrence->dayofweek); break; } if ($rcnt = $recurrence->occurrences) { $rrule->setRecurCount($rcnt); } if ($runtil = $recurrence->until) { $rrule->setRecurEnd(new Horde_Date($runtil)); } if ($interval = $recurrence->interval) { $rrule->setRecurInterval($interval); } return $rrule; }
public static function readRecurrenceForm($start, $timezone, $recurrence = null) { $recur = Horde_Util::getFormData('recur'); if (!strlen($recur)) { return $recurrence; } if (!isset($recurrence)) { $recurrence = new Horde_Date_Recurrence($start); } else { $recurrence->setRecurStart($start); } if (Horde_Util::getFormData('recur_end_type') == 'date') { if ($end_date = Horde_Util::getFormData('recur_end_date')) { // From ajax interface. $date_ob = Kronolith::parseDate($end_date, false); $recur_enddate = array('year' => $date_ob->year, 'month' => $date_ob->month, 'day' => $date_ob->mday); } else { // From traditional interface. $recur_enddate = Horde_Util::getFormData('recur_end'); } if ($recurrence->hasRecurEnd()) { $recurEnd = $recurrence->recurEnd; $recurEnd->month = $recur_enddate['month']; $recurEnd->mday = $recur_enddate['day']; $recurEnd->year = $recur_enddate['year']; } else { $recurEnd = new Horde_Date(array('hour' => 23, 'min' => 59, 'sec' => 59, 'month' => $recur_enddate['month'], 'mday' => $recur_enddate['day'], 'year' => $recur_enddate['year']), $timezone); } $recurrence->setRecurEnd($recurEnd); } elseif (Horde_Util::getFormData('recur_end_type') == 'count') { $recurrence->setRecurCount(Horde_Util::getFormData('recur_count')); } elseif (Horde_Util::getFormData('recur_end_type') == 'none') { $recurrence->setRecurCount(0); $recurrence->setRecurEnd(null); } $recurrence->setRecurType($recur); switch ($recur) { case Horde_Date_Recurrence::RECUR_DAILY: $recurrence->setRecurInterval(Horde_Util::getFormData('recur_daily_interval', 1)); break; case Horde_Date_Recurrence::RECUR_WEEKLY: $weekly = Horde_Util::getFormData('weekly'); $weekdays = 0; if (is_array($weekly)) { foreach ($weekly as $day) { $weekdays |= $day; } } if ($weekdays == 0) { // Sunday starts at 0. switch ($start->dayOfWeek()) { case 0: $weekdays |= Horde_Date::MASK_SUNDAY; break; case 1: $weekdays |= Horde_Date::MASK_MONDAY; break; case 2: $weekdays |= Horde_Date::MASK_TUESDAY; break; case 3: $weekdays |= Horde_Date::MASK_WEDNESDAY; break; case 4: $weekdays |= Horde_Date::MASK_THURSDAY; break; case 5: $weekdays |= Horde_Date::MASK_FRIDAY; break; case 6: $weekdays |= Horde_Date::MASK_SATURDAY; break; } } $recurrence->setRecurInterval(Horde_Util::getFormData('recur_weekly_interval', 1)); $recurrence->setRecurOnDay($weekdays); break; case Horde_Date_Recurrence::RECUR_MONTHLY_DATE: switch (Horde_Util::getFormData('recur_monthly_scheme')) { case Horde_Date_Recurrence::RECUR_MONTHLY_WEEKDAY: $recurrence->setRecurType(Horde_Date_Recurrence::RECUR_MONTHLY_WEEKDAY); case Horde_Date_Recurrence::RECUR_MONTHLY_DATE: $recurrence->setRecurInterval(Horde_Util::getFormData('recur_monthly') ? 1 : Horde_Util::getFormData('recur_monthly_interval', 1)); break; default: $recurrence->setRecurInterval(Horde_Util::getFormData('recur_day_of_month_interval', 1)); break; } break; case Horde_Date_Recurrence::RECUR_MONTHLY_WEEKDAY: $recurrence->setRecurInterval(Horde_Util::getFormData('recur_week_of_month_interval', 1)); break; case Horde_Date_Recurrence::RECUR_YEARLY_DATE: switch (Horde_Util::getFormData('recur_yearly_scheme')) { case Horde_Date_Recurrence::RECUR_YEARLY_WEEKDAY: case Horde_Date_Recurrence::RECUR_YEARLY_DAY: $recurrence->setRecurType(Horde_Util::getFormData('recur_yearly_scheme')); case Horde_Date_Recurrence::RECUR_YEARLY_DATE: $recurrence->setRecurInterval(Horde_Util::getFormData('recur_yearly') ? 1 : Horde_Util::getFormData('recur_yearly_interval', 1)); break; default: $recurrence->setRecurInterval(Horde_Util::getFormData('recur_yearly_interval', 1)); break; } break; case Horde_Date_Recurrence::RECUR_YEARLY_DAY: $recurrence->setRecurInterval(Horde_Util::getFormData('recur_yearly_day_interval', $yearly_interval)); break; case Horde_Date_Recurrence::RECUR_YEARLY_WEEKDAY: $recurrence->setRecurInterval(Horde_Util::getFormData('recur_yearly_weekday_interval', $yearly_interval)); break; } if ($exceptions = Horde_Util::getFormData('exceptions')) { foreach ($exceptions as $exception) { $recurrence->addException((int) substr($exception, 0, 4), (int) substr($exception, 4, 2), (int) substr($exception, 6, 2)); } } return $recurrence; }
/** * Imports a backend specific event object. * * @param mixed $event Backend specific event object that this object * will represent. */ public function fromDriver($event) { $this->id = '_' . $this->_api . $event['id']; $this->icon = !empty($event['icon']) ? $event['icon'] : null; $this->title = $event['title']; $this->description = isset($event['description']) ? $event['description'] : ''; if (isset($event['location'])) { $this->location = $event['location']; } try { $this->start = new Horde_Date($event['start']); $this->end = new Horde_Date($event['end']); } catch (Horde_Date_Exception $e) { throw new Kronolith_Exception($e); } if (isset($event['status'])) { switch ($event['status']) { case 'confirmed': $this->status = Kronolith::STATUS_CONFIRMED; break; case 'tentative': $this->status = Kronolith::STATUS_TENTATIVE; break; default: $this->status = Kronolith::STATUS_FREE; } } else { $this->status = Kronolith::STATUS_FREE; } if (isset($event['private'])) { $this->private = $event['private']; } $this->_params = $event['params']; $this->_link = !empty($event['link']) ? $event['link'] : null; $this->url = !empty($event['url']) ? (string) $event['url'] : null; $this->_editLink = !empty($event['edit_link']) ? $event['edit_link'] : null; $this->_deleteLink = !empty($event['delete_link']) ? $event['delete_link'] : null; $this->_ajaxLink = !empty($event['ajax_link']) ? $event['ajax_link'] : null; $this->_backgroundColor = Kronolith::backgroundColor($event); $this->_foregroundColor = Kronolith::foregroundColor($event); if (isset($event['recurrence'])) { $recurrence = new Horde_Date_Recurrence($this->start); $recurrence->setRecurType($event['recurrence']['type']); if (isset($event['recurrence']['end'])) { $recurrence->setRecurEnd(new Horde_Date($event['recurrence']['end'])); } if (isset($event['recurrence']['interval'])) { $recurrence->setRecurInterval($event['recurrence']['interval']); } if (isset($event['recurrence']['count'])) { $recurrence->setRecurCount($event['recurrence']['count']); } if (isset($event['recurrence']['days'])) { $recurrence->setRecurOnDay($event['recurrence']['days']); } if (isset($event['recurrence']['exceptions'])) { foreach ($event['recurrence']['exceptions'] as $exception) { $recurrence->addException(substr($exception, 0, 4), substr($exception, 4, 2), substr($exception, 6, 2)); } } if (isset($event['recurrence']['completions'])) { foreach ($event['recurrence']['completions'] as $completion) { $recurrence->addCompletion(substr($completion, 0, 4), substr($completion, 4, 2), substr($completion, 6, 2)); } } $this->recurrence = $recurrence; } if (isset($event['owner'])) { $this->_owner = $event['owner']; } if (isset($event['permissions'])) { $this->_permissions = $event['permissions']; } if (isset($event['variable_length'])) { $this->_variableLength = $event['variable_length']; } $this->initialized = true; $this->stored = true; }
/** * Parse recurrence properties. * * @param string $value MAPI stream * * @return Horde_Date_Recurrence * @throws Horde_Compress_Exception */ protected function _parseRecurrence($value) { $deleted = $modified = array(); // both are 0x3004 (version strings); $this->_geti($value, 16); $this->_geti($value, 16); $freq = $this->_geti($value, 16); $pattern = $this->_geti($value, 16); $calendarType = $this->_geti($value, 16); $firstDt = $this->_geti($value, 32); $period = $this->_geti($value, 32); // Only used for tasks, otherwise value must be zero. $flag = $this->_geti($value, 32); // TypeSpecific field switch ($pattern) { case Horde_Compress_Tnef::PATTERN_DAY: // Nothing here to see, move along. break; case Horde_Compress_Tnef::PATTERN_WEEK: // Bits: 0/unused, 1/Saturday, 2/Friday, 3/Thursday, 4/Wednesday, // 5/Tuesday, 6/Monday, 7/Sunday. $day = $this->_geti($value, 8); // ?? $this->_geti($value, 24); break; case Horde_Compress_Tnef::PATTERN_MONTH: case Horde_Compress_Tnef::PATTERN_MONTH_END: // Day of month on which the recurrence falls. $day = $this->_geti($value, 32); break; case Horde_Compress_Tnef::PATTERN_MONTH_NTH: // Bits: 0/unused, 1/Saturday, 2/Friday, 3/Thursday, 4/Wednesday, // 5/Tuesday, 6/Monday, 7/Sunday. // For Nth Weekday of month $day = $this->_geti($value, 8); $this->_geti($value, 24); $n = $this->_geti($value, 32); break; } $end = $this->_geti($value, 32); $count = $this->_geti($value, 32); $fdow = $this->_geti($value, 32); $deletedCount = $this->_geti($value, 32); for ($i = 0; $i < $deletedCount; $i++) { $deleted[] = $this->_geti($value, 32); } $modifiedCount = $this->_geti($value, 32); for ($i = 0; $i < $modifiedCount; $i++) { $modified[] = $this->_geti($value, 32); } // What Timezone are these in? try { $startDate = new Horde_Date(Horde_Mapi::filetimeToUnixtime($this->_geti($value, 32))); $endDate = new Horde_Date(Horde_Mapi::filetimeToUnixtime($this->_geti($value, 32))); } catch (Horde_Mapi_Exception $e) { throw new Horde_Compress_Exception($e); } catch (Horde_Date_Exception $e) { throw new Horde_Compress_Exception($e); } $rrule = new Horde_Date_Recurrence($startDate); switch ($pattern) { case Horde_Compress_Tnef::PATTERN_DAY: $rrule->setRecurType(Horde_Date_Recurrence::RECUR_DAILY); break; case Horde_Compress_Tnef::PATTERN_WEEK: $rrule->setRecurType(Horde_Date_Recurrence::RECUR_WEEKLY); break; case Horde_Compress_Tnef::PATTERN_MONTH: case Horde_Compress_Tnef::PATTERN_MONTH_END: $rrule->setRecurType(Horde_Date_Recurrence::RECUR_MONTHLY_DATE); break; case Horde_Compress_Tnef::PATTERN_MONTH_NTH: $rrule->setRecurType(Horde_Date_Recurrence::RECUR_MONTHLY_WEEKDAY); break; default: if ($freq == Horde_Compress_Tnef::RECUR_YEARLY) { $rrule->setRecurType(Horde_Date_Recurrence::RECUR_YEARLY); } } switch ($end) { case Horde_Compress_Tnef::RECUR_END_N: $rrule->setRecurCount($count); break; case Horde_Compress_Tnef::RECUR_END_DATE: $rrule->setRecurEnd($endDate); break; } return $rrule; }
public function testRecurringTasks() { $due = time() - 1; $recurrence = new Horde_Date_Recurrence($due); $recurrence->setRecurType(Horde_Date_Recurrence::RECUR_DAILY); $id = $this->_add(array('name' => 'TEST', 'desc' => 'Some test task.', 'due' => $due, 'recurrence' => $recurrence)); $due = new Horde_Date($due); $result = self::$driver->get($id[0]); $next = $result->getNextDue(); $this->assertInstanceOf('Horde_Date', $next); $this->assertEquals($due->timestamp(), $next->timestamp()); $result->toggleComplete(); $result->save(); $result2 = self::$driver->get($id[0]); $due->mday++; $next = $result2->getNextDue(); $this->assertInstanceOf('Horde_Date', $next); $this->assertEquals($due->timestamp(), $next->timestamp()); $result2->toggleComplete(); $result2->save(); $result3 = self::$driver->get($id[0]); $due->mday++; $next = $result3->getNextDue(); $this->assertInstanceOf('Horde_Date', $next); $this->assertEquals($due->timestamp(), $next->timestamp()); $this->assertFalse($result3->recurrence->hasCompletion($due->year, $due->month, $due->mday)); $due->mday--; $this->assertTrue($result3->recurrence->hasCompletion($due->year, $due->month, $due->mday)); $due->mday--; $this->assertTrue($result3->recurrence->hasCompletion($due->year, $due->month, $due->mday)); }
public function getInfo(&$vars, &$var, &$info) { $recur = $vars->recurrence; if (!$recur) { return; } $recurrence = new Horde_Date_Recurrence($this->_getDue($var, $vars)); if ($vars->recur_end_type == 'date') { $recurEnd = Nag::parseDate($vars->recur_end, false); $recurEnd->hour = 23; $recurEnd->min = $recurEnd->sec = 59; $recurrence->setRecurEnd($recurEnd); } elseif ($vars->recur_end_type == 'count') { $recurrence->setRecurCount($vars->recur_count); } elseif ($vars->recur_end_type == 'none') { $recurrence->setRecurCount(0); $recurrence->setRecurEnd(null); } $recurrence->setRecurType($recur); switch ($recur) { case Horde_Date_Recurrence::RECUR_DAILY: $recurrence->setRecurInterval($vars->get('recur_daily_interval', 1)); break; case Horde_Date_Recurrence::RECUR_WEEKLY: $weekly = $vars->weekly; $weekdays = 0; if (is_array($weekly)) { foreach ($weekly as $day) { $weekdays |= $day; } } if ($weekdays == 0) { // Sunday starts at 0. switch ($recurrence->start->dayOfWeek()) { case 0: $weekdays |= Horde_Date::MASK_SUNDAY; break; case 1: $weekdays |= Horde_Date::MASK_MONDAY; break; case 2: $weekdays |= Horde_Date::MASK_TUESDAY; break; case 3: $weekdays |= Horde_Date::MASK_WEDNESDAY; break; case 4: $weekdays |= Horde_Date::MASK_THURSDAY; break; case 5: $weekdays |= Horde_Date::MASK_FRIDAY; break; case 6: $weekdays |= Horde_Date::MASK_SATURDAY; break; } } $recurrence->setRecurInterval($vars->get('recur_weekly_interval', 1)); $recurrence->setRecurOnDay($weekdays); break; case Horde_Date_Recurrence::RECUR_MONTHLY_DATE: switch ($vars->recur_monthly_scheme) { case Horde_Date_Recurrence::RECUR_MONTHLY_WEEKDAY: $recurrence->setRecurType(Horde_Date_Recurrence::RECUR_MONTHLY_WEEKDAY); case Horde_Date_Recurrence::RECUR_MONTHLY_DATE: $recurrence->setRecurInterval($vars->recur_monthly ? 1 : $vars->get('recur_monthly_interval', 1)); break; default: $recurrence->setRecurInterval($vars->get('recur_day_of_month_interval', 1)); break; } break; case Horde_Date_Recurrence::RECUR_MONTHLY_WEEKDAY: $recurrence->setRecurInterval($vars->get('recur_week_of_month_interval', 1)); break; case Horde_Date_Recurrence::RECUR_YEARLY_DATE: switch ($vars->recur_yearly_scheme) { case Horde_Date_Recurrence::RECUR_YEARLY_WEEKDAY: case Horde_Date_Recurrence::RECUR_YEARLY_DAY: $recurrence->setRecurType($vars->recur_yearly_scheme); case Horde_Date_Recurrence::RECUR_YEARLY_DATE: $recurrence->setRecurInterval($vars->recur_yearly ? 1 : $vars->get('recur_yearly_interval', 1)); break; default: $recurrence->setRecurInterval($vars->get('recur_yearly_interval', 1)); break; } break; case Horde_Date_Recurrence::RECUR_YEARLY_DAY: $recurrence->setRecurInterval($vars->get('recur_yearly_day_interval', $yearly_interval)); break; case Horde_Date_Recurrence::RECUR_YEARLY_WEEKDAY: $recurrence->setRecurInterval($vars->get('recur_yearly_weekday_interval', $yearly_interval)); break; } if ($vars->exceptions) { foreach ($vars->exceptions as $exception) { $recurrence->addException((int) substr($exception, 0, 4), (int) substr($exception, 4, 2), (int) substr($exception, 6, 2)); } } $info = $recurrence; }
/** * Return an array describing this task from the provided backend data. * * @param array $row The backend data * @param boolean $include_history Include history data. * * @return array The task data. */ protected function _buildTask($row, $include_history = true) { // Make sure tasks always have a UID. if (empty($row['task_uid'])) { $row['task_uid'] = strval(new Horde_Support_Guid()); $query = 'UPDATE ' . $this->_params['table'] . ' SET task_uid = ?' . ' WHERE task_owner = ? AND task_id = ?'; $values = array($row['task_uid'], $row['task_owner'], $row['task_id']); try { $this->_db->update($query, $values); } catch (Horde_Db_Exception $e) { } } if (!$row['task_due'] || !$row['task_recurtype']) { $recurrence = null; } else { $recurrence = new Horde_Date_Recurrence($row['task_due']); $recurrence->setRecurType((int) $row['task_recurtype']); $recurrence->setRecurInterval((int) $row['task_recurinterval']); if (isset($row['task_recurenddate']) && $row['task_recurenddate'] != '9999-12-31 23:59:59') { $recur_end = new Horde_Date($row['task_recurenddate'], 'UTC'); $recur_end->setTimezone(date_default_timezone_get()); $recurrence->setRecurEnd($recur_end); } if (isset($row['task_recurcount'])) { $recurrence->setRecurCount((int) $row['task_recurcount']); } if (isset($row['task_recurdays'])) { $recurrence->recurData = (int) $row['task_recurdays']; } if (!empty($row['task_exceptions'])) { $recurrence->exceptions = explode(',', $row['task_exceptions']); } if (!empty($row['task_completions'])) { $recurrence->completions = explode(',', $row['task_completions']); } } /* Create a new task based on $row's values. */ $task = array('tasklist_id' => $row['task_owner'], 'task_id' => $row['task_id'], 'uid' => Horde_String::convertCharset($row['task_uid'], $this->_params['charset'], 'UTF-8'), 'parent' => $row['task_parent'], 'owner' => $row['task_creator'], 'assignee' => $row['task_assignee'], 'name' => Horde_String::convertCharset($row['task_name'], $this->_params['charset'], 'UTF-8'), 'desc' => Horde_String::convertCharset($row['task_desc'], $this->_params['charset'], 'UTF-8'), 'start' => $row['task_start'], 'due' => $row['task_due'], 'priority' => $row['task_priority'], 'estimate' => (double) $row['task_estimate'], 'completed' => $row['task_completed'], 'completed_date' => isset($row['task_completed_date']) ? $row['task_completed_date'] : null, 'alarm' => $row['task_alarm'], 'methods' => Horde_String::convertCharset(@unserialize($row['task_alarm_methods']), $this->_params['charset'], 'UTF-8'), 'private' => $row['task_private'], 'recurrence' => $recurrence); if ($include_history) { try { $userId = $GLOBALS['registry']->getAuth(); $log = $GLOBALS['injector']->getInstance('Horde_History')->getHistory('nag:' . $row['task_owner'] . ':' . $row['task_uid']); foreach ($log as $entry) { switch ($entry['action']) { case 'add': $task['created'] = new Horde_Date($entry['ts']); if ($userId != $entry['who']) { $task['createdby'] = sprintf(_("by %s"), Nag::getUserName($entry['who'])); } else { $task['createdby'] = _("by me"); } break; case 'modify': $task['modified'] = new Horde_Date($entry['ts']); if ($userId != $entry['who']) { $task['modifiedby'] = sprintf(_("by %s"), Nag::getUserName($entry['who'])); } else { $task['modifiedby'] = _("by me"); } break; } } } catch (Horde_Exception $e) { } } return $task; }
public function testEncodingSimpleExceptions() { $this->markTestSkipped('Needs updated fixture.'); $l = new Horde_Test_Log(); $logger = $l->getLogger(); //$logger = new Horde_Log_Logger(new Horde_Log_Handler_Stream(fopen('/tmp/test.log', 'a'))); // Every other week recurrence, on thursday, no end. $r = new Horde_Date_Recurrence('2011-12-01T15:00:00'); $r->setRecurType(Horde_Date_Recurrence::RECUR_WEEKLY); $r->setRecurInterval(2); $r->setRecurOnDay(Horde_Date::MASK_THURSDAY); $r->addException(2011, 12, 29); $e = new Horde_ActiveSync_Message_Exception(); $d = new Horde_Date('2011-12-29T15:00:00'); $e->setExceptionStartTime($d); $e->deleted = true; $appt = new Horde_ActiveSync_Message_Appointment(array('logger' => $logger)); $appt->setSubject('Event Title'); $appt->setBody('Event Description'); $appt->setLocation('Philadelphia, PA'); $start = new Horde_Date('2011-12-01T15:00:00'); $appt->setDatetime(array('start' => $start, 'end' => new Horde_Date('2011-12-01T16:00:00'), 'allday' => false)); $appt->setTimezone($start); $appt->setSensitivity(Horde_ActiveSync_Message_Appointment::SENSITIVITY_PERSONAL); $appt->setBusyStatus(Horde_ActiveSync_Message_Appointment::BUSYSTATUS_BUSY); $appt->setDTStamp($start->timestamp()); $appt->setRecurrence($r); $appt->addException($e); $stream = fopen('php://memory', 'w+'); $encoder = new Horde_ActiveSync_Wbxml_Encoder($stream); $encoder->setLogger($logger); $encoder->startTag(Horde_ActiveSync::SYNC_DATA); $appt->encodeStream($encoder); $encoder->endTag(); $fixture = file_get_contents(__DIR__ . '/fixtures/simpleexception.wbxml'); rewind($stream); $results = stream_get_contents($stream); fclose($stream); $this->assertEquals($fixture, $results); }
public function testRecurrenceObjectWithNonDefaultTimezones() { // date_default_timezone_get is Europe/Berlin $date = new Horde_Date('2011-10-01T15:00:00', 'America/New_York'); $rrule = new Horde_Date_Recurrence($date); $rrule->setRecurType(Horde_Date_Recurrence::RECUR_WEEKLY); $rrule->setRecurOnDay(Horde_Date::MASK_SATURDAY); $rrule->setRecurInterval(2); $after = new Horde_Date('2011-10-16'); $next = $rrule->nextRecurrence($after); $this->assertInstanceOf('Horde_Date', $next); $this->assertEquals('2011-10-29 15:00:00', (string) $next); $this->assertEquals('America/New_York', $next->timezone); }