Fix missing events on edges of the view time range (when client timezone is different than server tz) (T698)

This commit is contained in:
Aleksander Machniak 2015-08-18 12:39:55 +02:00
parent c67e78de61
commit a0ca17fb36
6 changed files with 64 additions and 18 deletions

View file

@ -251,14 +251,16 @@ class kolab_calendar extends kolab_storage_folder_api
public function list_events($start, $end, $search = null, $virtual = 1, $query = array(), $filter_query = null) public function list_events($start, $end, $search = null, $virtual = 1, $query = array(), $filter_query = null)
{ {
// convert to DateTime for comparisons // convert to DateTime for comparisons
// #5190: make the range a little bit wider
// to workaround possible timezone differences
try { try {
$start = new DateTime('@'.$start); $start = new DateTime('@' . ($start - 12 * 3600));
} }
catch (Exception $e) { catch (Exception $e) {
$start = new DateTime('@0'); $start = new DateTime('@0');
} }
try { try {
$end = new DateTime('@'.$end); $end = new DateTime('@' . ($end + 12 * 3600));
} }
catch (Exception $e) { catch (Exception $e) {
$end = new DateTime('today +10 years'); $end = new DateTime('today +10 years');

View file

@ -50,6 +50,7 @@ class kolab_storage_cache
protected $order_by = null; protected $order_by = null;
protected $limit = null; protected $limit = null;
protected $error = 0; protected $error = 0;
protected $server_timezone;
/** /**
@ -84,6 +85,7 @@ class kolab_storage_cache
$this->enabled = $rcmail->config->get('kolab_cache', false); $this->enabled = $rcmail->config->get('kolab_cache', false);
$this->folders_table = $this->db->table_name('kolab_folders'); $this->folders_table = $this->db->table_name('kolab_folders');
$this->cache_refresh = get_offset_sec($rcmail->config->get('kolab_cache_refresh', '12h')); $this->cache_refresh = get_offset_sec($rcmail->config->get('kolab_cache_refresh', '12h'));
$this->server_timezone = new DateTimeZone(date_default_timezone_get());
if ($this->enabled) { if ($this->enabled) {
// always read folder cache and lock state from DB master // always read folder cache and lock state from DB master
@ -1145,4 +1147,19 @@ class kolab_storage_cache
} }
} }
/**
* Converts DateTime or unix timestamp into sql date format
* using server timezone.
*/
protected function _convert_datetime($datetime)
{
if (is_object($datetime)) {
$dt = clone $datetime;
$dt->setTimeZone($this->server_timezone);
return $dt->format(self::DB_DATE_FORMAT);
}
else if ($datetime) {
return date(self::DB_DATE_FORMAT, $datetime);
}
}
} }

View file

@ -34,27 +34,27 @@ class kolab_storage_cache_event extends kolab_storage_cache
{ {
$sql_data = parent::_serialize($object); $sql_data = parent::_serialize($object);
$sql_data['dtstart'] = is_object($object['start']) ? $object['start']->format(self::DB_DATE_FORMAT) : date(self::DB_DATE_FORMAT, $object['start']); $sql_data['dtstart'] = $this->_convert_datetime($object['start']);
$sql_data['dtend'] = is_object($object['end']) ? $object['end']->format(self::DB_DATE_FORMAT) : date(self::DB_DATE_FORMAT, $object['end']); $sql_data['dtend'] = $this->_convert_datetime($object['end']);
// extend date range for recurring events // extend date range for recurring events
if ($object['recurrence'] && $object['_formatobj']) { if ($object['recurrence'] && $object['_formatobj']) {
$recurrence = new kolab_date_recurrence($object['_formatobj']); $recurrence = new kolab_date_recurrence($object['_formatobj']);
$dtend = $recurrence->end() ?: new DateTime('now +10 years'); $dtend = $recurrence->end() ?: new DateTime('now +10 years');
$sql_data['dtend'] = $dtend->format(self::DB_DATE_FORMAT); $sql_data['dtend'] = $this->_convert_datetime($dtend);
} }
// extend start/end dates to spawn all exceptions // extend start/end dates to spawn all exceptions
if (is_array($object['exceptions'])) { if (is_array($object['exceptions'])) {
foreach ($object['exceptions'] as $exception) { foreach ($object['exceptions'] as $exception) {
if (is_a($exception['start'], 'DateTime')) { if (is_a($exception['start'], 'DateTime')) {
$exstart = $exception['start']->format(self::DB_DATE_FORMAT); $exstart = $this->_convert_datetime($exception['start']);
if ($exstart < $sql_data['dtstart']) { if ($exstart < $sql_data['dtstart']) {
$sql_data['dtstart'] = $exstart; $sql_data['dtstart'] = $exstart;
} }
} }
if (is_a($exception['end'], 'DateTime')) { if (is_a($exception['end'], 'DateTime')) {
$exend = $exception['end']->format(self::DB_DATE_FORMAT); $exend = $this->_convert_datetime($exception['end']);
if ($exend > $sql_data['dtend']) { if ($exend > $sql_data['dtend']) {
$sql_data['dtend'] = $exend; $sql_data['dtend'] = $exend;
} }

View file

@ -24,4 +24,19 @@
class kolab_storage_cache_freebusy extends kolab_storage_cache class kolab_storage_cache_freebusy extends kolab_storage_cache
{ {
protected $extra_cols = array('dtstart','dtend'); protected $extra_cols = array('dtstart','dtend');
/**
* Helper method to convert the given Kolab object into a dataset to be written to cache
*
* @override
*/
protected function _serialize($object)
{
$sql_data = parent::_serialize($object) + array('dtstart' => null, 'dtend' => null);
$sql_data['dtstart'] = $this->_convert_datetime($object['start']);
$sql_data['dtend'] = $this->_convert_datetime($object['end']);
return $sql_data;
}
} }

View file

@ -25,4 +25,18 @@ class kolab_storage_cache_journal extends kolab_storage_cache
{ {
protected $extra_cols = array('dtstart','dtend'); protected $extra_cols = array('dtstart','dtend');
/**
* Helper method to convert the given Kolab object into a dataset to be written to cache
*
* @override
*/
protected function _serialize($object)
{
$sql_data = parent::_serialize($object) + array('dtstart' => null, 'dtend' => null);
$sql_data['dtstart'] = $this->_convert_datetime($object['start']);
$sql_data['dtend'] = $this->_convert_datetime($object['end']);
return $sql_data;
}
} }

View file

@ -32,12 +32,10 @@ class kolab_storage_cache_task extends kolab_storage_cache
*/ */
protected function _serialize($object) protected function _serialize($object)
{ {
$sql_data = parent::_serialize($object) + array('dtstart' => null, 'dtend' => null); $sql_data = parent::_serialize($object);
if ($object['start']) $sql_data['dtstart'] = $this->_convert_datetime($object['start']);
$sql_data['dtstart'] = is_object($object['start']) ? $object['start']->format(self::DB_DATE_FORMAT) : date(self::DB_DATE_FORMAT, $object['start']); $sql_data['dtend'] = $this->_convert_datetime($object['due']);
if ($object['due'])
$sql_data['dtend'] = is_object($object['due']) ? $object['due']->format(self::DB_DATE_FORMAT) : date(self::DB_DATE_FORMAT, $object['due']);
return $sql_data; return $sql_data;
} }