summaryrefslogtreecommitdiff
path: root/plugins/libkolab/lib/kolab_date_recurrence.php
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/libkolab/lib/kolab_date_recurrence.php')
-rw-r--r--plugins/libkolab/lib/kolab_date_recurrence.php113
1 files changed, 84 insertions, 29 deletions
diff --git a/plugins/libkolab/lib/kolab_date_recurrence.php b/plugins/libkolab/lib/kolab_date_recurrence.php
index 3aaa399..9eeeca1 100644
--- a/plugins/libkolab/lib/kolab_date_recurrence.php
+++ b/plugins/libkolab/lib/kolab_date_recurrence.php
@@ -3,8 +3,7 @@
/**
* Recurrence computation class for xcal-based Kolab format objects
*
- * Utility class to compute instances of recurring events.
- * It requires the libcalendaring PHP module to be installed and loaded.
+ * Uitility class to compute instances of recurring events.
*
* @version @package_version@
* @author Thomas Bruederli <bruederli@kolabsys.com>
@@ -26,31 +25,43 @@
*/
class kolab_date_recurrence
{
- private /* EventCal */ $engine;
- private /* kolab_format_xcal */ $object;
- private /* DateTime */ $start;
- private /* DateTime */ $next;
- private /* cDateTime */ $cnext;
- private /* DateInterval */ $duration;
+ private $engine;
+ private $object;
+ private $next;
+ private $duration;
+ private $tz_offset = 0;
+ private $dst_start = 0;
+ private $allday = false;
+ private $hour = 0;
/**
* Default constructor
*
* @param array The Kolab object to operate on
*/
- function __construct($object)
+ function __construct($event)
{
- $data = $object->to_array();
+ $this->object = $object = $event->to_array();
+ $this->next = new Horde_Date($object['start'], kolab_format::$timezone->getName());
- $this->object = $object;
- $this->engine = $object->to_libcal();
- $this->start = $this->next = $data['start'];
- $this->cnext = kolab_format::get_datetime($this->next);
-
- if (is_object($data['start']) && is_object($data['end']))
- $this->duration = $data['start']->diff($data['end']);
+ if (is_object($object['start']) && is_object($object['end']))
+ $this->duration = $object['start']->diff($object['end']);
else
- $this->duration = new DateInterval('PT' . ($data['end'] - $data['start']) . 'S');
+ $this->duration = new DateInterval('PT' . ($object['end'] - $object['start']) . 'S');
+
+ // use (copied) Horde classes to compute recurring instances
+ // TODO: replace with something that has less than 6'000 lines of code
+ $this->engine = new Horde_Date_Recurrence($this->next);
+ $this->engine->fromRRule20($this->to_rrule($object['recurrence'])); // TODO: get that string directly from libkolabxml
+
+ foreach ((array)$object['recurrence']['EXDATE'] as $exdate)
+ $this->engine->addException($exdate->format('Y'), $exdate->format('n'), $exdate->format('j'));
+
+ $now = new DateTime('now', kolab_format::$timezone);
+ $this->tz_offset = $object['allday'] ? $now->getOffset() - date('Z') : 0;
+ $this->dst_start = $this->next->format('I');
+ $this->allday = $object['allday'];
+ $this->hour = $this->next->hour;
}
/**
@@ -62,14 +73,20 @@ class kolab_date_recurrence
public function next_start($timestamp = false)
{
$time = false;
-
- if ($this->engine && $this->next) {
- if (($cnext = new cDateTime($this->engine->getNextOccurence($this->cnext))) && $cnext->isValid()) {
- $next = kolab_format::php_datetime($cnext);
- $time = $timestamp ? $next->format('U') : $next;
- $this->cnext = $cnext;
- $this->next = $next;
+ if ($this->next && ($next = $this->engine->nextActiveRecurrence(array('year' => $this->next->year, 'month' => $this->next->month, 'mday' => $this->next->mday + 1, 'hour' => $this->next->hour, 'min' => $this->next->min, 'sec' => $this->next->sec)))) {
+ if ($this->allday) {
+ $next->hour = $this->hour; # fix time for all-day events
+ $next->min = 0;
+ }
+ if ($timestamp) {
+ # consider difference in daylight saving between base event and recurring instance
+ $dst_diff = ($this->dst_start - $next->format('I')) * 3600;
+ $time = $next->timestamp() - $this->tz_offset - $dst_diff;
}
+ else {
+ $time = $next->toDateTime();
+ }
+ $this->next = $next;
}
return $time;
@@ -86,7 +103,7 @@ class kolab_date_recurrence
$next_end = clone $next_start;
$next_end->add($this->duration);
- $next = $this->object->to_array();
+ $next = $this->object;
$next['recurrence_id'] = $next_start->format('Y-m-d');
$next['start'] = $next_start;
$next['end'] = $next_end;
@@ -106,11 +123,49 @@ class kolab_date_recurrence
*/
public function end($limit = 'now +1 year')
{
- $limit_dt = new DateTime($limit);
- if ($this->engine && ($cend = $this->engine->getLastOccurrence()) && ($end_dt = kolab_format::php_datetime(new cDateTime($cend))) && $end_dt < $limit_dt) {
- return $end_dt->format('U');
+ if ($this->object['recurrence']['UNTIL'])
+ return $this->object['recurrence']['UNTIL']->format('U');
+
+ $limit_time = strtotime($limit);
+ while ($next_start = $this->next_start(true)) {
+ if ($next_start > $limit_time)
+ break;
+ }
+
+ if ($this->next) {
+ $next_end = $this->next->toDateTime();
+ $next_end->add($this->duration);
+ return $next_end->format('U');
}
return false;
}
+
+ /**
+ * Convert the internal structured data into a vcalendar RRULE 2.0 string
+ */
+ private function to_rrule($recurrence)
+ {
+ if (is_string($recurrence))
+ return $recurrence;
+
+ $rrule = '';
+ foreach ((array)$recurrence as $k => $val) {
+ $k = strtoupper($k);
+ switch ($k) {
+ case 'UNTIL':
+ $val = $val->format('Ymd\THis');
+ break;
+ case 'EXDATE':
+ foreach ((array)$val as $i => $ex)
+ $val[$i] = $ex->format('Ymd\THis');
+ $val = join(',', (array)$val);
+ break;
+ }
+ $rrule .= $k . '=' . $val . ';';
+ }
+
+ return $rrule;
+ }
+
}