Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F174659
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
33 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/kolab_sync_timezone_converter.php b/lib/kolab_sync_timezone_converter.php
index 95fcddf..cceeb36 100644
--- a/lib/kolab_sync_timezone_converter.php
+++ b/lib/kolab_sync_timezone_converter.php
@@ -1,669 +1,674 @@
<?php
/**
+--------------------------------------------------------------------------+
| Kolab Sync (ActiveSync for Kolab) |
| |
| Copyright (C) 2011-2017, Kolab Systems AG <contact@kolabsys.com> |
| Copyright (C) 2008-2012, Metaways Infosystems GmbH |
| |
| This program is free software: you can redistribute it and/or modify |
| it under the terms of the GNU Affero General Public License as published |
| by the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/> |
+--------------------------------------------------------------------------+
| Author: Aleksander Machniak <machniak@kolabsys.com> |
| Author: Jonas Fischer <j.fischer@metaways.de> |
+--------------------------------------------------------------------------+
*/
/**
* Activesync timezone converter
*/
class kolab_sync_timezone_converter
{
/**
* holds the instance of the singleton
*
* @var kolab_sync_timezone_onverter
*/
private static $_instance = NULL;
protected $_startDate = array();
/**
* If set then the timezone guessing results will be cached.
* This is strongly recommended for performance reasons.
*
* @var rcube_cache
*/
protected $cache = null;
/**
* array of offsets known by ActiceSync clients, but unknown by php
* @var array
*/
protected $_knownTimezones = array(
'0AIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==' => array(
'Pacific/Kwajalein' => 'MHT'
)
);
/**
* don't use the constructor. Use the singleton.
*
* @param $_logger
*/
private function __construct()
{
}
/**
* don't clone. Use the singleton.
*/
private function __clone()
{
}
/**
* the singleton pattern
*
* @return kolab_sync_timezone_converter
*/
public static function getInstance()
{
if (self::$_instance === NULL) {
self::$_instance = new kolab_sync_timezone_converter();
}
return self::$_instance;
}
/**
* Returns a timezone with an offset matching the time difference
* of $dt from $referenceDt.
*
* If set and matching the offset, kolab_format::$timezone is preferred.
*
* @param DateTime $dt The date time value for which we
* calculate the offset.
* @param DateTime $referenceDt The reference value, for instance in UTC.
*
* @return DateTimeZone|null
*/
public function getOffsetTimezone($dt, $referenceDt)
{
$interval = $referenceDt->diff($dt);
$tz = new DateTimeZone($interval->format('%R%H%I')); //e.g. +0200
$utcOffset = $tz->getOffset($dt);
//Prefer the configured timezone if it matches the offset.
if (kolab_format::$timezone) {
if (kolab_format::$timezone->getOffset($dt) == $utcOffset) {
return kolab_format::$timezone;
}
}
//Look for any timezone with a matching offset.
foreach (DateTimeZone::listIdentifiers() as $timezoneIdentifier) {
$timezone = new DateTimeZone($timezoneIdentifier);
if ($timezone->getOffset($dt) == $utcOffset) {
return $timezone;
}
}
return null;
}
/**
* Returns a list of timezones that match to the {@param $_offsets}
*
* If {@see $_expectedTimezone} is set then the method will terminate as soon
* as the expected timezone has matched and the expected timezone will be the
* first entry to the returned array.
*
* @param string|array $_offsets
*
* @return array
*/
public function getListOfTimezones($_offsets)
{
if (is_string($_offsets) && isset($this->_knownTimezones[$_offsets])) {
$timezones = $this->_knownTimezones[$_offsets];
}
else {
if (is_string($_offsets)) {
// unpack timezone info to array
$_offsets = $this->_unpackTimezoneInfo($_offsets);
}
if (!$this->_validateOffsets($_offsets)) {
return array();
}
$this->_setDefaultStartDateIfEmpty($_offsets);
$cacheId = $this->_getCacheId('timezones', $_offsets);
$timezones = $this->_loadFromCache($cacheId);
if (!is_array($timezones)) {
$timezones = array();
foreach (DateTimeZone::listIdentifiers() as $timezoneIdentifier) {
$timezone = new DateTimeZone($timezoneIdentifier);
if (false !== ($matchingTransition = $this->_checkTimezone($timezone, $_offsets))) {
$timezones[$timezoneIdentifier] = $matchingTransition['abbr'];
}
}
$this->_saveInCache($timezones, $cacheId);
}
}
return $timezones;
}
/**
* Returns PHP timezone that matches to the {@param $_offsets}
*
* If {@see $_expectedTimezone} is set then the method will return this timezone if it matches.
*
* @param string|array $_offsets Activesync timezone definition
* @param string $_expectedTomezone Expected timezone name
*
* @return string Expected timezone name
*/
public function getTimezone($_offsets, $_expectedTimezone = null)
{
$timezones = $this->getListOfTimezones($_offsets);
if ($_expectedTimezone && isset($timezones[$_expectedTimezone])) {
return $_expectedTimezone;
}
else {
return key($timezones);
}
}
/**
* Return packed string for given {@param $_timezone}
*
* @param string $_timezone Timezone identifier
* @param string|int $_startDate Start date
*
* @return string Packed timezone offsets
*/
public function encodeTimezone($_timezone, $_startDate = null)
{
foreach ($this->_knownTimezones as $packedString => $knownTimezone) {
if (array_key_exists($_timezone, $knownTimezone)) {
return $packedString;
}
}
$offsets = $this->getOffsetsForTimezone($_timezone, $_startDate);
return $this->_packTimezoneInfo($offsets);
}
/**
* Get offsets for given timezone
*
* @param string $_timezone Timezone identifier
* @param string|int $_startDate Start date
*
* @return array Timezone offsets
*/
public function getOffsetsForTimezone($_timezone, $_startDate = null)
{
$this->_setStartDate($_startDate);
$cacheId = $this->_getCacheId('offsets', array($_timezone));
if (false === ($offsets = $this->_loadFromCache($cacheId))) {
$offsets = $this->_getOffsetsTemplate();
try {
$timezone = new DateTimeZone($_timezone);
}
catch (Exception $e) {
return null;
}
list($standardTransition, $daylightTransition) = $this->_getTransitionsForTimezoneAndYear($timezone, $this->_startDate['year']);
if ($standardTransition) {
$offsets['bias'] = $standardTransition['offset']/60*-1;
if ($daylightTransition) {
$offsets = $this->_generateOffsetsForTransition($offsets, $standardTransition, 'standard', $timezone);
$offsets = $this->_generateOffsetsForTransition($offsets, $daylightTransition, 'daylight', $timezone);
//@todo how do we get the standardBias (is usually 0)?
//$offsets['standardBias'] = ...
$offsets['daylightBias'] = ($daylightTransition['offset'] - $standardTransition['offset'])/60*-1;
$offsets['standardHour'] -= $offsets['daylightBias'] / 60;
$offsets['daylightHour'] += $offsets['daylightBias'] / 60;
}
}
$this->_saveInCache($offsets, $cacheId);
}
return $offsets;
}
/**
* Get offsets for timezone transition
*
* @param array $_offsets Timezone offsets
* @param array $_transition Timezone transition information
* @param string $_type Transition type: 'standard' or 'daylight'
* @param DateTimeZone $_timezone Timezone of the transition
*
* @return array
*/
protected function _generateOffsetsForTransition(array $_offsets, array $_transition, $_type, $_timezone)
{
$transitionDate = new DateTime($_transition['time'], $_timezone);
if ($_transition['offset']) {
$transitionDate->modify($_transition['offset'] . ' seconds');
}
$_offsets[$_type . 'Month'] = (int) $transitionDate->format('n');
$_offsets[$_type . 'DayOfWeek'] = (int) $transitionDate->format('w');
$_offsets[$_type . 'Minute'] = (int) $transitionDate->format('i');
$_offsets[$_type . 'Hour'] = (int) $transitionDate->format('G');
for ($i=5; $i>0; $i--) {
if ($this->_isNthOcurrenceOfWeekdayInMonth($transitionDate, $i)) {
- $_offsets[$_type . 'Day'] = $i;
+ $_offsets[$_type . 'Week'] = $i;
break;
};
}
return $_offsets;
}
/**
* Test if the weekday of the given {@param $_timestamp} is the {@param $_occurence}th occurence of this weekday within its month.
*
* @param DateTime $_datetime
* @param int $_occurence [1 to 5, where 5 indicates the final occurrence during the month if that day of the week does not occur 5 times]
*
* @return bool
*/
protected function _isNthOcurrenceOfWeekdayInMonth($_datetime, $_occurence)
{
if ($_occurence <= 1) {
return true;
}
$orig = $_datetime->format('n');
if ($_occurence == 5) {
$modified = clone($_datetime);
$modified->modify('1 week');
$mod = $modified->format('n');
// modified date is a next month
return $mod > $orig || ($mod == 1 && $orig == 12);
}
$modified = clone($_datetime);
$modified->modify(sprintf('-%d weeks', $_occurence - 1));
$mod = $modified->format('n');
if ($mod != $orig) {
return false;
}
$modified = clone($_datetime);
$modified->modify(sprintf('-%d weeks', $_occurence));
$mod = $modified->format('n');
// modified month is earlier than original
return $mod < $orig || ($mod == 12 && $orig == 1);
}
/**
* Check if the given {@param $_standardTransition} and {@param $_daylightTransition}
* match to the object property {@see $_offsets}
*
* @param array $standardTransition
* @param array $daylightTransition
*
* @return bool
*/
protected function _checkTransition($_standardTransition, $_daylightTransition, $_offsets, $tz)
{
if (empty($_standardTransition) || empty($_offsets)) {
return false;
}
$standardOffset = ($_offsets['bias'] + $_offsets['standardBias']) * 60 * -1;
// check each condition in a single if statement and break the chain when one condition is not met - for performance reasons
- if ($standardOffset == $_standardTransition['offset'] ) {
+ if ($standardOffset == $_standardTransition['offset']) {
if (empty($_offsets['daylightMonth']) && (empty($_daylightTransition) || empty($_daylightTransition['isdst']))) {
// No DST
return true;
}
$daylightOffset = ($_offsets['bias'] + $_offsets['daylightBias']) * 60 * -1;
// the milestone is sending a positive value for daylightBias while it should send a negative value
$daylightOffsetMilestone = ($_offsets['bias'] + ($_offsets['daylightBias'] * -1) ) * 60 * -1;
if (
!empty($_daylightTransition)
&& ($daylightOffset == $_daylightTransition['offset'] || $daylightOffsetMilestone == $_daylightTransition['offset'])
) {
- $standardDate = new DateTime($_standardTransition['time'], $tz);
- $daylightDate = new DateTime($_daylightTransition['time'], $tz);
+ // date-time input here contains UTC timezone specifier (+0000),
+ // we have to convert the date to the requested timezone afterwards.
+ $standardDate = new DateTime($_standardTransition['time']);
+ $daylightDate = new DateTime($_daylightTransition['time']);
+ $standardDate->setTimezone($tz);
+ $daylightDate->setTimezone($tz);
if ($standardDate->format('n') == $_offsets['standardMonth'] &&
$daylightDate->format('n') == $_offsets['daylightMonth'] &&
$standardDate->format('w') == $_offsets['standardDayOfWeek'] &&
$daylightDate->format('w') == $_offsets['daylightDayOfWeek']
) {
- return $this->_isNthOcurrenceOfWeekdayInMonth($daylightDate, $_offsets['daylightDay']) &&
- $this->_isNthOcurrenceOfWeekdayInMonth($standardDate, $_offsets['standardDay']);
+ return $this->_isNthOcurrenceOfWeekdayInMonth($daylightDate, $_offsets['daylightWeek']) &&
+ $this->_isNthOcurrenceOfWeekdayInMonth($standardDate, $_offsets['standardWeek']);
}
}
}
return false;
}
/**
* decode timezone info from activesync
*
* @param string $_packedTimezoneInfo the packed timezone info
* @return array
*/
protected function _unpackTimezoneInfo($_packedTimezoneInfo)
{
- $timezoneUnpackString = 'lbias/a64standardName/vstandardYear/vstandardMonth/vstandardDayOfWeek/vstandardDay/vstandardHour/vstandardMinute/vstandardSecond/vstandardMilliseconds/lstandardBias/a64daylightName/vdaylightYear/vdaylightMonth/vdaylightDayOfWeek/vdaylightDay/vdaylightHour/vdaylightMinute/vdaylightSecond/vdaylightMilliseconds/ldaylightBias';
+ $timezoneUnpackString = 'lbias/a64standardName/vstandardYear/vstandardMonth/vstandardDayOfWeek/vstandardWeek/vstandardHour/vstandardMinute/vstandardSecond/vstandardMilliseconds/lstandardBias'
+ . '/a64daylightName/vdaylightYear/vdaylightMonth/vdaylightDayOfWeek/vdaylightWeek/vdaylightHour/vdaylightMinute/vdaylightSecond/vdaylightMilliseconds/ldaylightBias';
$timezoneInfo = unpack($timezoneUnpackString, base64_decode($_packedTimezoneInfo));
if ($timezoneInfo['standardHour'] == 23 && $timezoneInfo['standardMilliseconds'] == 999
&& $timezoneInfo['standardMinute'] == 59 && $timezoneInfo['standardSecond'] == 59
) {
$timezoneInfo['standardHour'] = 24;
$timezoneInfo['standardMinute'] = 0;
$timezoneInfo['standardSecond'] = 0;
$timezoneInfo['standardMilliseconds'] = 0;
}
return $timezoneInfo;
}
/**
* encode timezone info to activesync
*
* @param array $_timezoneInfo
* @return string
*/
protected function _packTimezoneInfo($_timezoneInfo)
{
if (!is_array($_timezoneInfo)) {
return null;
}
// According to e.g. https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-systemtime,
// 24 is not allowed in the Hour field, and consequently Outlook can't deal with it.
// This is the same workaround that Outlook applies.
if ($_timezoneInfo['standardHour'] == 24) {
$_timezoneInfo['standardHour'] = 23;
$_timezoneInfo['standardMinute'] = 59;
$_timezoneInfo['standardSecond'] = 59;
$_timezoneInfo['standardMilliseconds'] = 999;
}
$packed = pack(
"la64vvvvvvvvla64vvvvvvvvl",
$_timezoneInfo['bias'],
$_timezoneInfo['standardName'],
$_timezoneInfo['standardYear'],
$_timezoneInfo['standardMonth'],
$_timezoneInfo['standardDayOfWeek'],
- $_timezoneInfo['standardDay'],
+ $_timezoneInfo['standardWeek'],
$_timezoneInfo['standardHour'],
$_timezoneInfo['standardMinute'],
$_timezoneInfo['standardSecond'],
$_timezoneInfo['standardMilliseconds'],
$_timezoneInfo['standardBias'],
$_timezoneInfo['daylightName'],
$_timezoneInfo['daylightYear'],
$_timezoneInfo['daylightMonth'],
$_timezoneInfo['daylightDayOfWeek'],
- $_timezoneInfo['daylightDay'],
+ $_timezoneInfo['daylightWeek'],
$_timezoneInfo['daylightHour'],
$_timezoneInfo['daylightMinute'],
$_timezoneInfo['daylightSecond'],
$_timezoneInfo['daylightMilliseconds'],
$_timezoneInfo['daylightBias']
);
return base64_encode($packed);
}
/**
* Returns complete offsets array with all fields empty
*
* Used e.g. when reverse-generating ActiveSync Timezone Offset Information
* based on a given Timezone, {@see getOffsetsForTimezone}
*
* @return unknown_type
*/
protected function _getOffsetsTemplate()
{
return array(
'bias' => 0,
'standardName' => '',
'standardYear' => 0,
'standardMonth' => 0,
'standardDayOfWeek' => 0,
- 'standardDay' => 0,
+ 'standardWeek' => 0,
'standardHour' => 0,
'standardMinute' => 0,
'standardSecond' => 0,
'standardMilliseconds' => 0,
'standardBias' => 0,
'daylightName' => '',
'daylightYear' => 0,
'daylightMonth' => 0,
'daylightDayOfWeek' => 0,
- 'daylightDay' => 0,
+ 'daylightWeek' => 0,
'daylightHour' => 0,
'daylightMinute' => 0,
'daylightSecond' => 0,
'daylightMilliseconds' => 0,
'daylightBias' => 0
);
}
/**
* Validate and set offsets
*
* @param array $value
*
* @return bool Validation result
*/
protected function _validateOffsets($value)
{
// validate $value
- if ((!empty($value['standardMonth']) || !empty($value['standardDay']) || !empty($value['daylightMonth']) || !empty($value['daylightDay'])) &&
- (empty($value['standardMonth']) || empty($value['standardDay']) || empty($value['daylightMonth']) || empty($value['daylightDay']))
+ if ((!empty($value['standardMonth']) || !empty($value['standardWeek']) || !empty($value['daylightMonth']) || !empty($value['daylightWeek'])) &&
+ (empty($value['standardMonth']) || empty($value['standardWeek']) || empty($value['daylightMonth']) || empty($value['daylightWeek']))
) {
// It is not possible not set standard offsets without setting daylight offsets and vice versa
return false;
}
return true;
}
/**
* Parse and set object property {@see $_startDate}
*
* @param string|int $_startDate
* @return void
*/
protected function _setStartDate($_startDate)
{
if (empty($_startDate)) {
$this->_setDefaultStartDateIfEmpty();
return;
}
$startDateParsed = array();
if (is_string($_startDate)) {
$startDateParsed['string'] = $_startDate;
$startDateParsed['ts'] = strtotime($_startDate);
}
else if (is_int($_startDate)) {
$startDateParsed['ts'] = $_startDate;
$startDateParsed['string'] = strftime('%F', $_startDate);
}
else {
$this->_setDefaultStartDateIfEmpty();
return;
}
$startDateParsed['object'] = new DateTime($startDateParsed['string']);
$startDateParsed = array_merge($startDateParsed, getdate($startDateParsed['ts']));
$this->_startDate = $startDateParsed;
}
/**
* Set default value for object property {@see $_startdate} if it is not set yet.
* Tries to guess the correct startDate depending on object property {@see $_offsets} and
* falls back to current date.
*
* @param array $_offsets [offsets may be avaluated for a given start year]
* @return void
*/
protected function _setDefaultStartDateIfEmpty($_offsets = null)
{
if (!empty($this->_startDate)) {
return;
}
if (!empty($_offsets['standardYear'])) {
$this->_setStartDate($_offsets['standardYear'].'-01-01');
}
else {
$this->_setStartDate(time());
}
}
/**
* Check if the given {@param $_timezone} matches the {@see $_offsets}
* and also evaluate the daylight saving time transitions for this timezone if necessary.
*
* @param DateTimeZone $timezone
* @param array $offsets
*
* @return array|bool
*/
protected function _checkTimezone(DateTimeZone $timezone, $offsets)
{
list($standardTransition, $daylightTransition) = $this->_getTransitionsForTimezoneAndYear($timezone, $this->_startDate['year']);
if ($this->_checkTransition($standardTransition, $daylightTransition, $offsets, $timezone)) {
return $standardTransition;
}
return false;
}
/**
* Returns the standard and daylight transitions for the given {@param $_timezone}
* and {@param $_year}.
*
* @param DateTimeZone $_timezone
* @param int $_year
*
* @return array
*/
protected function _getTransitionsForTimezoneAndYear(DateTimeZone $_timezone, $_year)
{
$standardTransition = null;
$daylightTransition = null;
$start = mktime(0, 0, 0, 12, 1, $_year - 1);
$end = mktime(24, 0, 0, 12, 31, $_year);
$transitions = $_timezone->getTransitions($start, $end);
if ($transitions === false) {
return array();
}
foreach ($transitions as $index => $transition) {
if (strftime('%Y', $transition['ts']) == $_year) {
if (isset($transitions[$index+1]) && strftime('%Y', $transitions[$index]['ts']) == strftime('%Y', $transitions[$index+1]['ts'])) {
$daylightTransition = $transition['isdst'] ? $transition : $transitions[$index+1];
$standardTransition = $transition['isdst'] ? $transitions[$index+1] : $transition;
}
else {
$daylightTransition = $transition['isdst'] ? $transition : null;
$standardTransition = $transition['isdst'] ? null : $transition;
}
break;
}
else if ($index == count($transitions) -1) {
$standardTransition = $transition;
}
}
return array($standardTransition, $daylightTransition);
}
protected function _getCacheId($_prefix, $_offsets)
{
return $_prefix . md5(serialize($_offsets));
}
protected function _loadFromCache($key)
{
if ($cache = $this->getCache()) {
return $cache->get($key);
}
return false;
}
protected function _saveInCache($value, $key)
{
if ($cache = $this->getCache()) {
$cache->set($key, $value);
}
}
/**
* Getter for the cache engine object
*/
protected function getCache()
{
if ($this->cache === null) {
$rcube = rcube::get_instance();
$cache = $rcube->get_cache_shared('activesync');
$this->cache = $cache ? $cache : false;
}
return $this->cache;
}
}
diff --git a/tests/timezone_converter.php b/tests/timezone_converter.php
index 743b76d..623a399 100644
--- a/tests/timezone_converter.php
+++ b/tests/timezone_converter.php
@@ -1,128 +1,161 @@
<?php
class timezone_converter extends PHPUnit\Framework\TestCase
{
function setUp()
{
}
function test_list_timezones()
{
- date_default_timezone_set('America/Los_Angeles');
+// date_default_timezone_set('America/Los_Angeles');
$converter = timezone_converter_test::getInstance();
-
- $input = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAEAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAEAAAAAAAAAxP///w==';
- $output = $converter->getListOfTimezones($input);
+ $output = $converter->getListOfTimezones('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAEAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAEAAAAAAAAAxP///w==');
$this->assertTrue(is_array($output));
+ $this->assertSame(array(), $output);
$converter = timezone_converter_test::getInstance();
$output = $converter->getListOfTimezones('xP///0MAZQBuAHQAcgBhAGwAIABFAHUAcgBvAHAAZQAgAFMAdABhAG4AZABhAHIAZAAgAFQAaQBtAGUAAAAAAAAAAAAAAAoAAAAFAAMAAAAAAAAAAAAAAEMAZQBuAHQAcgBhAGwAIABFAHUAcgBvAHAAZQAgAEQAYQB5AGwAaQBnAGgAdAAgAFQAaQBtAGUAAAAAAAAAAAAAAAMAAAAFAAIAAAAAAAAAxP///w==');
$this->assertTrue(is_array($output));
$this->assertTrue(isset($output['Europe/Warsaw']));
$converter = timezone_converter_test::getInstance();
$output = $converter->getListOfTimezones('4AEAAFAAYQBjAGkAZgBpAGMAIABTAHQAYQBuAGQAYQByAGQAIABUAGkAbQBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAABAAIAAAAAAAAAAAAAAFAAYQBjAGkAZgBpAGMAIABEAGEAeQBsAGkAZwBoAHQAIABUAGkAbQBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAACAAIAAAAAAAAAxP///w==');
$this->assertTrue(is_array($output));
$this->assertTrue(isset($output['America/Los_Angeles']));
+
+ $converter = timezone_converter_test::getInstance();
+ $output = $converter->getListOfTimezones('Lv///0kAcgBhAG4AIABTAHQAYQBuAGQAYQByAGQAIABUAGkAbQBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkAAgADABcAOwA7AOcDAAAAAEkAcgBhAG4AIABEAGEAeQBsAGkAZwBoAHQAIABUAGkAbQBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAQAEAAAAAAAAAAAAxP///w==');
+
+ $this->assertTrue(is_array($output));
+ $this->assertTrue(isset($output['Asia/Tehran']));
}
function test_get_timezone()
{
date_default_timezone_set('America/Los_Angeles');
$converter = timezone_converter_test::getInstance();
$datetime = new DateTime('2017-01-01T12:00:00Z');
$offsets = $converter->getOffsetsForTimezone('UTC', $datetime);
$output = $converter->getTimezone($offsets, 'UTC');
$this->assertSame('UTC', $output);
$offsets = $converter->getOffsetsForTimezone('Europe/Warsaw', $datetime);
$output = $converter->getTimezone($offsets, 'Europe/Warsaw');
$this->assertSame('Europe/Warsaw', $output);
$offsets = $converter->getOffsetsForTimezone('America/Los_Angeles', $datetime);
$output = $converter->getTimezone($offsets, 'America/Los_Angeles');
$this->assertSame('America/Los_Angeles', $output);
}
function test_get_offsets_for_timezone()
{
date_default_timezone_set('America/Los_Angeles');
$converter = timezone_converter_test::getInstance();
$datetime = new DateTime('2017-01-01T12:00:00Z');
$output = $converter->getOffsetsForTimezone('UTC', $datetime);
$this->assertSame($output['bias'], 0);
$this->assertSame($output['standardBias'], 0);
$this->assertSame($output['daylightBias'], 0);
$this->assertSame($output['standardMonth'], 0);
$this->assertSame($output['daylightMonth'], 0);
$output = $converter->getOffsetsForTimezone('Europe/Warsaw', $datetime);
$this->assertSame($output['standardBias'], 0);
$this->assertSame($output['standardMonth'], 10);
- $this->assertSame($output['standardDay'], 5);
+ $this->assertSame($output['standardWeek'], 5);
$this->assertSame($output['standardHour'], 3);
$this->assertSame($output['daylightBias'], -60);
$this->assertSame($output['daylightMonth'], 3);
- $this->assertSame($output['daylightDay'], 5);
+ $this->assertSame($output['daylightWeek'], 5);
$this->assertSame($output['daylightHour'], 2);
$output = $converter->getOffsetsForTimezone('America/Los_Angeles', $datetime);
$this->assertSame($output['bias'], 480);
$this->assertSame($output['standardBias'], 0);
$this->assertSame($output['standardMonth'], 11);
- $this->assertSame($output['standardDay'], 1);
+ $this->assertSame($output['standardWeek'], 1);
$this->assertSame($output['standardHour'], 2);
$this->assertSame($output['daylightBias'], -60);
$this->assertSame($output['daylightMonth'], 3);
- $this->assertSame($output['daylightDay'], 2);
+ $this->assertSame($output['daylightWeek'], 2);
$this->assertSame($output['daylightHour'], 2);
$output = $converter->getOffsetsForTimezone('Atlantic/Azores', $datetime);
$this->assertSame($output['bias'], 60);
$this->assertSame($output['standardBias'], 0);
$this->assertSame($output['standardMonth'], 10);
- $this->assertSame($output['standardDay'], 5);
+ $this->assertSame($output['standardWeek'], 5);
$this->assertSame($output['standardHour'], 1);
$this->assertSame($output['daylightBias'], -60);
$this->assertSame($output['daylightMonth'], 3);
- $this->assertSame($output['daylightDay'], 5);
+ $this->assertSame($output['daylightWeek'], 5);
$this->assertSame($output['daylightHour'], 0);
$output = $converter->getOffsetsForTimezone('Asia/Tehran', $datetime);
$this->assertSame($output['bias'], -210);
$this->assertSame($output['standardBias'], 0);
$this->assertSame($output['standardMonth'], 9);
- $this->assertSame($output['standardDay'], 3);
+ $this->assertSame($output['standardWeek'], 3);
+ $this->assertSame($output['standardDayOfWeek'], 2);
$this->assertSame($output['standardHour'], 24);
$this->assertSame($output['daylightBias'], -60);
$this->assertSame($output['daylightMonth'], 3);
- $this->assertSame($output['daylightDay'], 4);
+ $this->assertSame($output['daylightWeek'], 4);
+ $this->assertSame($output['daylightDayOfWeek'], 1);
$this->assertSame($output['daylightHour'], 0);
}
+
+ function data_timezone_conversion()
+ {
+ return array(
+ array('Asia/Tehran', 'Lv///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkAAgADABcAOwA7AOcDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAQAEAAAAAAAAAAAAxP///w=='),
+ array('Pacific/Pago_Pago', 'lAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=='),
+ array('Europe/Warsaw', 'xP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAIAAAAAAAAAxP///w=='),
+ );
+ }
+
+ /**
+ * @dataProvider data_timezone_conversion
+ */
+ function test_timezone_conversion($tz, $expected)
+ {
+ $datetime = new DateTime('2021-07-01T12:00:00Z');
+ $converter = timezone_converter_test::getInstance();
+ $output = $converter->encodeTimezone($tz, $datetime);
+
+ $this->assertSame($expected, $output);
+
+ $output = $converter->getListOfTimezones($output);
+
+ $this->assertTrue(is_array($output));
+ $this->assertTrue(isset($output[$tz]));
+ }
}
class timezone_converter_test extends kolab_sync_timezone_converter
{
// disable cache
function getCache()
{
return null;
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Jan 18, 9:38 PM (10 h, 34 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
120015
Default Alt Text
(33 KB)
Attached To
Mode
R4 syncroton
Attached
Detach File
Event Timeline
Log In to Comment