Providing support for timezone adjustments in date/time conversion methods
This commit is contained in:
parent
63c5cbc98e
commit
53a32ce7f7
|
@ -67,18 +67,26 @@ class PHPExcel_Shared_Date
|
|||
* @private
|
||||
* @var int
|
||||
*/
|
||||
private static $ExcelBaseDate = self::CALENDAR_WINDOWS_1900;
|
||||
private static $_excelBaseDate = self::CALENDAR_WINDOWS_1900;
|
||||
|
||||
/*
|
||||
* Default Timezone used for date/time conversions
|
||||
*
|
||||
* @private
|
||||
* @var string
|
||||
*/
|
||||
private static $_timezone = 'UTC';
|
||||
|
||||
/**
|
||||
* Set the Excel calendar (Windows 1900 or Mac 1904)
|
||||
*
|
||||
* @param integer $baseDate Excel base date
|
||||
* @param integer $baseDate Excel base date (1900 or 1904)
|
||||
* @return boolean Success or failure
|
||||
*/
|
||||
public static function setExcelCalendar($baseDate) {
|
||||
if (($baseDate == self::CALENDAR_WINDOWS_1900) ||
|
||||
($baseDate == self::CALENDAR_MAC_1904)) {
|
||||
self::$ExcelBaseDate = $baseDate;
|
||||
self::$_excelBaseDate = $baseDate;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
|
@ -88,33 +96,116 @@ class PHPExcel_Shared_Date
|
|||
/**
|
||||
* Return the Excel calendar (Windows 1900 or Mac 1904)
|
||||
*
|
||||
* @return integer $baseDate Excel base date
|
||||
* @return integer Excel base date (1900 or 1904)
|
||||
*/
|
||||
public static function getExcelCalendar() {
|
||||
return self::$ExcelBaseDate;
|
||||
return self::$_excelBaseDate;
|
||||
} // function getExcelCalendar()
|
||||
|
||||
|
||||
/**
|
||||
* Validate a Timezone value
|
||||
*
|
||||
* @param string $timezone Time zone (e.g. 'Europe/London')
|
||||
* @return boolean Success or failure
|
||||
*/
|
||||
private static function _validateTimezone($timezone) {
|
||||
if (in_array($timezone, DateTimeZone::listIdentifiers())) {
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Default Timezone used for date/time conversions
|
||||
*
|
||||
* @param string $timezone Time zone (e.g. 'Europe/London')
|
||||
* @return boolean Success or failure
|
||||
*/
|
||||
public static function setTimezone($timezone) {
|
||||
if (self::_validateTimezone($timezone)) {
|
||||
self::$_timezone = $timezone;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
} // function setTimezone()
|
||||
|
||||
|
||||
/**
|
||||
* Return the Default Timezone used for date/time conversions
|
||||
*
|
||||
* @return string Timezone (e.g. 'Europe/London')
|
||||
*/
|
||||
public static function getTimezone() {
|
||||
return self::$_timezone;
|
||||
} // function getTimezone()
|
||||
|
||||
|
||||
/**
|
||||
* Return the Timezone offset used for date/time conversions to/from UST
|
||||
* This requires both the timezone and the calculated date/time to allow for local DST
|
||||
*
|
||||
* @param string $timezone The timezone for finding the adjustment to UST
|
||||
* @param integer $timestamp PHP date/time value
|
||||
* @return integer Number of seconds for timezone adjustment
|
||||
* @throws PHPExcel_Exception
|
||||
*/
|
||||
private static function _getTimezoneAdjustment($timezone, $timestamp) {
|
||||
if ($timezone !== NULL) {
|
||||
if (!self::_validateTimezone($timezone)) {
|
||||
throw new PHPExcel_Exception("Invalid timezone " . $timezone);
|
||||
}
|
||||
} else {
|
||||
$timezone = self::$_timezone;
|
||||
}
|
||||
|
||||
if ($timezone == 'UST') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$objTimezone = new DateTimeZone($timezone);
|
||||
if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
|
||||
$transitions = $objTimezone->getTransitions($timestamp,$timestamp);
|
||||
} else {
|
||||
$allTransitions = $objTimezone->getTransitions();
|
||||
$transitions = array();
|
||||
foreach($allTransitions as $key => $transition) {
|
||||
if ($transition['ts'] > $timestamp) {
|
||||
$transitions[] = ($key > 0) ? $allTransitions[$key - 1] : $transitions1[] = $transition;
|
||||
break;
|
||||
}
|
||||
if (empty($transitions)) {
|
||||
$transitions[] = end($allTransitions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (count($transitions) > 0) ? $transitions[0]['offset'] : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a date from Excel to PHP
|
||||
*
|
||||
* @param long $dateValue Excel date/time value
|
||||
* @param boolean $adjustToTimezone Flag indicating whether $dateValue should be treated as
|
||||
* a UST timestamp, or adjusted to UST
|
||||
* @param string $timezone The timezone for finding the adjustment from UST
|
||||
* @return long PHP serialized date/time
|
||||
*/
|
||||
public static function ExcelToPHP($dateValue = 0) {
|
||||
if (self::$ExcelBaseDate == self::CALENDAR_WINDOWS_1900) {
|
||||
$myExcelBaseDate = 25569;
|
||||
public static function ExcelToPHP($dateValue = 0, $adjustToTimezone = FALSE, $timezone = NULL) {
|
||||
if (self::$_excelBaseDate == self::CALENDAR_WINDOWS_1900) {
|
||||
$my_excelBaseDate = 25569;
|
||||
// Adjust for the spurious 29-Feb-1900 (Day 60)
|
||||
if ($dateValue < 60) {
|
||||
--$myExcelBaseDate;
|
||||
--$my_excelBaseDate;
|
||||
}
|
||||
} else {
|
||||
$myExcelBaseDate = 24107;
|
||||
$my_excelBaseDate = 24107;
|
||||
}
|
||||
|
||||
// Perform conversion
|
||||
if ($dateValue >= 1) {
|
||||
$utcDays = $dateValue - $myExcelBaseDate;
|
||||
$utcDays = $dateValue - $my_excelBaseDate;
|
||||
$returnValue = round($utcDays * 86400);
|
||||
if (($returnValue <= PHP_INT_MAX) && ($returnValue >= -PHP_INT_MAX)) {
|
||||
$returnValue = (integer) $returnValue;
|
||||
|
@ -126,8 +217,10 @@ class PHPExcel_Shared_Date
|
|||
$returnValue = (integer) gmmktime($hours, $mins, $secs);
|
||||
}
|
||||
|
||||
$timezoneAdjustment = ($adjustToTimezone) ? self::_getTimezoneAdjustment($timezone, $returnValue) : 0;
|
||||
|
||||
// Return
|
||||
return $returnValue;
|
||||
return $returnValue + $timezoneAdjustment;
|
||||
} // function ExcelToPHP()
|
||||
|
||||
|
||||
|
@ -159,7 +252,7 @@ class PHPExcel_Shared_Date
|
|||
* @return mixed Excel date/time value
|
||||
* or boolean FALSE on failure
|
||||
*/
|
||||
public static function PHPToExcel($dateValue = 0) {
|
||||
public static function PHPToExcel($dateValue = 0, $adjustToTimezone = FALSE, $timezone = NULL) {
|
||||
$saveTimeZone = date_default_timezone_get();
|
||||
date_default_timezone_set('UTC');
|
||||
$retValue = FALSE;
|
||||
|
@ -190,16 +283,16 @@ class PHPExcel_Shared_Date
|
|||
* @return long Excel date/time value
|
||||
*/
|
||||
public static function FormattedPHPToExcel($year, $month, $day, $hours=0, $minutes=0, $seconds=0) {
|
||||
if (self::$ExcelBaseDate == self::CALENDAR_WINDOWS_1900) {
|
||||
if (self::$_excelBaseDate == self::CALENDAR_WINDOWS_1900) {
|
||||
//
|
||||
// Fudge factor for the erroneous fact that the year 1900 is treated as a Leap Year in MS Excel
|
||||
// This affects every date following 28th February 1900
|
||||
//
|
||||
$excel1900isLeapYear = TRUE;
|
||||
if (($year == 1900) && ($month <= 2)) { $excel1900isLeapYear = FALSE; }
|
||||
$myExcelBaseDate = 2415020;
|
||||
$my_excelBaseDate = 2415020;
|
||||
} else {
|
||||
$myExcelBaseDate = 2416481;
|
||||
$my_excelBaseDate = 2416481;
|
||||
$excel1900isLeapYear = FALSE;
|
||||
}
|
||||
|
||||
|
@ -214,7 +307,7 @@ class PHPExcel_Shared_Date
|
|||
// Calculate the Julian Date, then subtract the Excel base date (JD 2415020 = 31-Dec-1899 Giving Excel Date of 0)
|
||||
$century = substr($year,0,2);
|
||||
$decade = substr($year,2,2);
|
||||
$excelDate = floor((146097 * $century) / 4) + floor((1461 * $decade) / 4) + floor((153 * $month + 2) / 5) + $day + 1721119 - $myExcelBaseDate + $excel1900isLeapYear;
|
||||
$excelDate = floor((146097 * $century) / 4) + floor((1461 * $decade) / 4) + floor((153 * $month + 2) / 5) + $day + 1721119 - $my_excelBaseDate + $excel1900isLeapYear;
|
||||
|
||||
$excelTime = (($hours * 3600) + ($minutes * 60) + $seconds) / 86400;
|
||||
|
||||
|
|
|
@ -34,6 +34,30 @@ class DateTest extends PHPUnit_Framework_TestCase
|
|||
$this->assertFalse($result);
|
||||
}
|
||||
|
||||
public function testSetTimezone()
|
||||
{
|
||||
$timezoneValues = array(
|
||||
'Europe/Prague',
|
||||
'Asia/Tokyo',
|
||||
'America/Indiana/Indianapolis',
|
||||
'Pacific/Honolulu',
|
||||
'Atlantic/St_Helena',
|
||||
);
|
||||
|
||||
foreach($timezoneValues as $timezoneValue) {
|
||||
$result = call_user_func(array('PHPExcel_Shared_Date','setTimezone'),$timezoneValue);
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function testSetTimezoneWithInvalidValue()
|
||||
{
|
||||
$unsupportedTimezone = 'Etc/GMT+10';
|
||||
$result = call_user_func(array('PHPExcel_Shared_Date','setTimezone'),$unsupportedTimezone);
|
||||
$this->assertFalse($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerDateTimeExcelToPHP1900
|
||||
*/
|
||||
|
@ -161,4 +185,28 @@ class DateTest extends PHPUnit_Framework_TestCase
|
|||
return new testDataFileIterator('rawTestData/Shared/DateTimeFormatCodes.data');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerDateTimeExcelToPHP1900Timezone
|
||||
*/
|
||||
public function testDateTimeExcelToPHP1900Timezone()
|
||||
{
|
||||
$result = call_user_func(
|
||||
array('PHPExcel_Shared_Date','setExcelCalendar'),
|
||||
PHPExcel_Shared_Date::CALENDAR_WINDOWS_1900
|
||||
);
|
||||
|
||||
$args = func_get_args();
|
||||
$expectedResult = array_pop($args);
|
||||
if ($args[0] < 1) {
|
||||
$expectedResult += gmmktime(0,0,0);
|
||||
}
|
||||
$result = call_user_func_array(array('PHPExcel_Shared_Date','ExcelToPHP'),$args);
|
||||
$this->assertEquals($expectedResult, $result);
|
||||
}
|
||||
|
||||
public function providerDateTimeExcelToPHP1900Timezone()
|
||||
{
|
||||
return new testDataFileIterator('rawTestData/Shared/DateTimeExcelToPHP1900Timezone.data');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
#Excel DateTimeStamp Adjust Timezone Result Comments
|
||||
22269, TRUE, 'America/New_York', -285138000 // 19-Dec-1960 00:00:00 UST
|
||||
25569, TRUE, 'America/New_York', -18000 // PHP Base Date 01-Jan-1970 00:00:00 UST
|
||||
30292, TRUE, 'America/New_York', 408049200 // 07-Dec-1982 00:00:00 UST
|
||||
39611, TRUE, 'America/New_York', 1213214400 // 12-Jun-2008 00:00:00 UST
|
||||
50424, TRUE, 'America/New_York', 2147454000 // PHP 32-bit Latest Date 19-Jan-2038 00:00:00 UST
|
||||
22345.56789, TRUE, 'America/New_York', -278522534 // 18-May-1903 13:37:46 UST
|
||||
22345.6789, TRUE, 'America/New_York', -278512943 // 18-Oct-1933 16:17:37 UST
|
||||
0.5, TRUE, 'America/New_York', 28800 // 12:00:00 UST
|
||||
0.75, TRUE, 'America/New_York', 50400 // 18:00.00 UST
|
||||
0.12345, TRUE, 'America/New_York', -3734 // 02:57:46 UST
|
||||
41215, TRUE, 'America/New_York', 1351800000 // 02-Nov-2012 00:00:00 UST
|
||||
22269, TRUE, 'Pacific/Auckland', -285076800 // 19-Dec-1960 00:00:00 UST
|
||||
25569, TRUE, 'Pacific/Auckland', 43200 // PHP Base Date 01-Jan-1970 00:00:00 UST
|
||||
30292, TRUE, 'Pacific/Auckland', 408114000 // 07-Dec-1982 00:00:00 UST
|
||||
39611, TRUE, 'Pacific/Auckland', 1213272000 // 12-Jun-2008 00:00:00 UST
|
||||
50423.5, TRUE, 'Pacific/Auckland', 2147475600 // PHP 32-bit Latest Date 19-Jan-2038 00:00:00 UST
|
||||
22345.56789, TRUE, 'Pacific/Auckland', -278461334 // 18-May-1903 13:37:46 UST
|
||||
22345.6789, TRUE, 'Pacific/Auckland', -278451743 // 18-Oct-1933 16:17:37 UST
|
||||
0.5, TRUE, 'Pacific/Auckland', 90000 // 12:00:00 UST
|
||||
0.75, TRUE, 'Pacific/Auckland', 111600 // 18:00.00 UST
|
||||
0.12345, TRUE, 'Pacific/Auckland', 57466 // 02:57:46 UST
|
||||
41215, TRUE, 'Pacific/Auckland', 1351861200 // 02-Nov-2012 00:00:00 UST
|
|
@ -1,6 +1,6 @@
|
|||
"PHPExcel", "8053"
|
||||
"Mark Baker", "877D"
|
||||
"I<3Am3l1a/*", "E3C8"
|
||||
"!+&=()~§±æþ", "C0EA"
|
||||
"μυστικό κωδικό πρόσβασης", "FFFF26DD"
|
||||
"গোপন পাসওয়ার্ড", "E858"
|
||||
"Секретный пароль", "EA5F"
|
||||
|
|
Loading…
Reference in New Issue