Fix handling EXDATEs in different timezone than the event timezone (Bifrost#T154553)
This commit is contained in:
parent
779af09a68
commit
83ac298cd7
4 changed files with 59 additions and 29 deletions
|
@ -325,10 +325,13 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
// skip the first instance of a recurring event if listed in exdate
|
||||
if ($virtual && !empty($event['recurrence']['EXDATE'])) {
|
||||
$event_date = $event['start']->format('Ymd');
|
||||
$exdates = (array)$event['recurrence']['EXDATE'];
|
||||
$event_tz = $event['start']->getTimezone();
|
||||
|
||||
foreach ($exdates as $exdate) {
|
||||
if ($exdate->format('Ymd') == $event_date) {
|
||||
foreach ((array) $event['recurrence']['EXDATE'] as $exdate) {
|
||||
$ex = clone $exdate;
|
||||
$ex->setTimezone($event_tz);
|
||||
|
||||
if ($ex->format('Ymd') == $event_date) {
|
||||
$add = false;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1072,19 +1072,18 @@ class libvcalendar implements Iterator
|
|||
|
||||
// add EXDATEs each one per line (for Thunderbird Lightning)
|
||||
if (is_array($exdates)) {
|
||||
foreach ($exdates as $ex) {
|
||||
if ($ex instanceof \DateTime) {
|
||||
$exd = clone $event['start'];
|
||||
$exd->setDate($ex->format('Y'), $ex->format('n'), $ex->format('j'));
|
||||
$exd->setTimeZone(new \DateTimeZone('UTC'));
|
||||
$ve->add($this->datetime_prop($cal, 'EXDATE', $exd, true));
|
||||
foreach ($exdates as $exdate) {
|
||||
if ($exdate instanceof DateTime) {
|
||||
$ve->add($this->datetime_prop($cal, 'EXDATE', $exdate));
|
||||
}
|
||||
}
|
||||
}
|
||||
// add RDATEs
|
||||
if (!empty($rdates)) {
|
||||
foreach ((array)$rdates as $rdate) {
|
||||
$ve->add($this->datetime_prop($cal, 'RDATE', $rdate));
|
||||
if (is_array($rdates)) {
|
||||
foreach ($rdates as $rdate) {
|
||||
if ($ex instanceof DateTime) {
|
||||
$ve->add($this->datetime_prop($cal, 'RDATE', $rdate));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -203,17 +203,20 @@ abstract class kolab_format
|
|||
* @param mixed Date/Time value either as unix timestamp, date string or PHP DateTime object
|
||||
* @param DateTimeZone The timezone the date/time is in. Use global default if Null, local time if False
|
||||
* @param boolean True of the given date has no time component
|
||||
* @return object The libkolabxml date/time object
|
||||
* @param DateTimeZone The timezone to convert the date to before converting to cDateTime
|
||||
*
|
||||
* @return cDateTime The libkolabxml date/time object
|
||||
*/
|
||||
public static function get_datetime($datetime, $tz = null, $dateonly = false)
|
||||
public static function get_datetime($datetime, $tz = null, $dateonly = false, $dest_tz = null)
|
||||
{
|
||||
// use timezone information from datetime of global setting
|
||||
// use timezone information from datetime or global setting
|
||||
if (!$tz && $tz !== false) {
|
||||
if ($datetime instanceof DateTime)
|
||||
$tz = $datetime->getTimezone();
|
||||
if (!$tz)
|
||||
$tz = self::$timezone;
|
||||
}
|
||||
|
||||
$result = new cDateTime();
|
||||
|
||||
try {
|
||||
|
@ -225,14 +228,26 @@ abstract class kolab_format
|
|||
else if (is_string($datetime) && strlen($datetime)) {
|
||||
$datetime = $tz ? new DateTime($datetime, $tz) : new DateTime($datetime);
|
||||
}
|
||||
else if ($datetime instanceof DateTime) {
|
||||
$datetime = clone $datetime;
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {}
|
||||
|
||||
if ($datetime instanceof DateTime) {
|
||||
if ($dest_tz instanceof DateTimeZone && $dest_tz !== $datetime->getTimezone()) {
|
||||
$datetime->setTimezone($dest_tz);
|
||||
$tz = $dest_tz;
|
||||
}
|
||||
|
||||
$result->setDate($datetime->format('Y'), $datetime->format('n'), $datetime->format('j'));
|
||||
|
||||
if (!$dateonly)
|
||||
$result->setTime($datetime->format('G'), $datetime->format('i'), $datetime->format('s'));
|
||||
if ($dateonly) {
|
||||
// Dates should be always in local time only
|
||||
return $result;
|
||||
}
|
||||
|
||||
$result->setTime($datetime->format('G'), $datetime->format('i'), $datetime->format('s'));
|
||||
|
||||
// libkolabxml throws errors on some deprecated timezone names
|
||||
$utc_aliases = array('UTC', 'GMT', '+00:00', 'Z', 'Etc/GMT', 'Etc/UTC');
|
||||
|
@ -254,16 +269,19 @@ abstract class kolab_format
|
|||
/**
|
||||
* Convert the given cDateTime into a PHP DateTime object
|
||||
*
|
||||
* @param object cDateTime The libkolabxml datetime object
|
||||
* @return object DateTime PHP datetime instance
|
||||
* @param cDateTime The libkolabxml datetime object
|
||||
* @param DateTimeZone The timezone to convert the date to
|
||||
*
|
||||
* @return DateTime PHP datetime instance
|
||||
*/
|
||||
public static function php_datetime($cdt)
|
||||
public static function php_datetime($cdt, $dest_tz = null)
|
||||
{
|
||||
if (!is_object($cdt) || !$cdt->isValid())
|
||||
if (!is_object($cdt) || !$cdt->isValid()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$d = new DateTime;
|
||||
$d->setTimezone(self::$timezone);
|
||||
$d->setTimezone($dest_tz ?: self::$timezone);
|
||||
|
||||
try {
|
||||
if ($tzs = $cdt->timezone()) {
|
||||
|
|
|
@ -174,6 +174,10 @@ abstract class kolab_format_xcal extends kolab_format
|
|||
}
|
||||
}
|
||||
|
||||
if ($object['start'] instanceof DateTime) {
|
||||
$start_tz = $object['start']->getTimezone();
|
||||
}
|
||||
|
||||
// read recurrence rule
|
||||
if (($rr = $this->obj->recurrenceRule()) && $rr->isValid()) {
|
||||
$rrule_type_map = array_flip($this->rrule_type_map);
|
||||
|
@ -185,7 +189,7 @@ abstract class kolab_format_xcal extends kolab_format
|
|||
if (($count = $rr->count()) && $count > 0) {
|
||||
$object['recurrence']['COUNT'] = $count;
|
||||
}
|
||||
else if ($until = self::php_datetime($rr->end())) {
|
||||
else if ($until = self::php_datetime($rr->end(), $start_tz)) {
|
||||
$refdate = $this->get_reference_date();
|
||||
if ($refdate && $refdate instanceof DateTime && !$refdate->_dateonly) {
|
||||
$until->setTime($refdate->format('G'), $refdate->format('i'), 0);
|
||||
|
@ -214,16 +218,18 @@ abstract class kolab_format_xcal extends kolab_format
|
|||
|
||||
if ($exdates = $this->obj->exceptionDates()) {
|
||||
for ($i=0; $i < $exdates->size(); $i++) {
|
||||
if ($exdate = self::php_datetime($exdates->get($i)))
|
||||
if ($exdate = self::php_datetime($exdates->get($i), $start_tz)) {
|
||||
$object['recurrence']['EXDATE'][] = $exdate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($rdates = $this->obj->recurrenceDates()) {
|
||||
for ($i=0; $i < $rdates->size(); $i++) {
|
||||
if ($rdate = self::php_datetime($rdates->get($i)))
|
||||
if ($rdate = self::php_datetime($rdates->get($i), $start_tz)) {
|
||||
$object['recurrence']['RDATE'][] = $rdate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -415,6 +421,10 @@ abstract class kolab_format_xcal extends kolab_format
|
|||
$this->obj->setOrganizer($organizer);
|
||||
}
|
||||
|
||||
if ($object['start'] instanceof DateTime) {
|
||||
$start_tz = $object['start']->getTimezone();
|
||||
}
|
||||
|
||||
// save recurrence rule
|
||||
$rr = new RecurrenceRule;
|
||||
$rr->setFrequency(RecurrenceRule::FreqNone);
|
||||
|
@ -470,13 +480,13 @@ abstract class kolab_format_xcal extends kolab_format
|
|||
if ($object['recurrence']['COUNT'])
|
||||
$rr->setCount(intval($object['recurrence']['COUNT']));
|
||||
else if ($object['recurrence']['UNTIL'])
|
||||
$rr->setEnd(self::get_datetime($object['recurrence']['UNTIL'], null, true));
|
||||
$rr->setEnd(self::get_datetime($object['recurrence']['UNTIL'], null, true, $start_tz));
|
||||
|
||||
if ($rr->isValid()) {
|
||||
// add exception dates (only if recurrence rule is valid)
|
||||
$exdates = new vectordatetime;
|
||||
foreach ((array)$object['recurrence']['EXDATE'] as $exdate)
|
||||
$exdates->push(self::get_datetime($exdate, null, true));
|
||||
$exdates->push(self::get_datetime($exdate, null, true, $start_tz));
|
||||
$this->obj->setExceptionDates($exdates);
|
||||
}
|
||||
else {
|
||||
|
@ -494,7 +504,7 @@ abstract class kolab_format_xcal extends kolab_format
|
|||
if (!empty($object['recurrence']['RDATE'])) {
|
||||
$rdates = new vectordatetime;
|
||||
foreach ((array)$object['recurrence']['RDATE'] as $rdate)
|
||||
$rdates->push(self::get_datetime($rdate, null, true));
|
||||
$rdates->push(self::get_datetime($rdate, null, true, $start_tz));
|
||||
$this->obj->setRecurrenceDates($rdates);
|
||||
}
|
||||
|
||||
|
@ -760,7 +770,7 @@ abstract class kolab_format_xcal extends kolab_format
|
|||
$error_logged = true;
|
||||
rcube::raise_error(array(
|
||||
'code' => 900,
|
||||
'message' => "required kolabcalendaring module not found"
|
||||
'message' => "Required kolabcalendaring module not found"
|
||||
), true);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue