Skip to content

Commit 6221dae

Browse files
committed
Fix missing timezone conversion
1 parent 9e6581d commit 6221dae

File tree

1 file changed

+56
-1
lines changed

1 file changed

+56
-1
lines changed

src/ActiveExcelSheet.php

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?php
22
namespace codemix\excelexport;
33

4+
use Yii;
45
use yii\helpers\ArrayHelper;
56

67
/**
@@ -186,12 +187,29 @@ public function getFormatters()
186187
foreach ($attrs as $c => $attr) {
187188
switch ($types[$c]->type) {
188189
case 'date':
190+
$this->_formatters[$c] = function ($v) {
191+
if (empty($v)) {
192+
return null;
193+
} else {
194+
// Set the correct timezone before converting to a UNIX timestamp.
195+
// This prevents dates from being altered due to timezone
196+
// conversion, e.g.
197+
// '2017-12-05 00:00:00' could become
198+
// '2017-12-04 23:00:00'
199+
$timezone = date_default_timezone_get();
200+
date_default_timezone_set(Yii::$app->formatter->defaultTimeZone);
201+
$timestamp = strtotime($v);
202+
date_default_timezone_set($timezone);
203+
return \PHPExcel_Shared_Date::PHPToExcel($timestamp);
204+
}
205+
};
206+
break;
189207
case 'datetime':
190208
$this->_formatters[$c] = function ($v) {
191209
if (empty($v)) {
192210
return null;
193211
} else {
194-
return \PHPExcel_Shared_Date::PHPToExcel(strtotime($v));
212+
return \PHPExcel_Shared_Date::PHPToExcel($this->toExcelTime($v));
195213
}
196214
};
197215
break;
@@ -249,6 +267,43 @@ protected function renderRow($data, $row, $formats, $formatters, $callbacks, $ty
249267
return parent::renderRow($values, $row, $formats, $formatters, $callbacks, $types);
250268
}
251269

270+
/**
271+
* Convert a datetime to the right excel timestamp
272+
*
273+
* This method will use [[\yii\i18n\Formatter::defaultTimeZone]] and
274+
* [[\yii\base\Application::timeZone]] to convert the given datetime
275+
* from DB to application timezone.
276+
*
277+
* @param string $value the datetime value
278+
* @return int timezone offset in seconds
279+
* @see [[yii\i18n\Formatter::defaultTimeZone]]
280+
* @see [[yii\base\Application::timeZone]]
281+
*/
282+
protected function toExcelTime($value)
283+
{
284+
// "Cached" timezone instances
285+
static $defaultTimezone;
286+
static $timezone;
287+
288+
if (Yii::$app->formatter->defaultTimeZone === Yii::$app->timeZone) {
289+
return strtotime($value);
290+
} else {
291+
if ($timezone === null) {
292+
$defaultTimezone = new \DateTimeZone(Yii::$app->formatter->defaultTimeZone);
293+
$timezone = new \DateTimeZone(Yii::$app->timeZone);
294+
}
295+
296+
// Offset can depend on given datetime due to DST
297+
$defaultDatetime = new \DateTime($value, $defaultTimezone);
298+
$offset = $timezone->getOffset($defaultDatetime);
299+
300+
// PHPExcel_Shared_Date::PHPToExcel() method expects a
301+
// "pseudo-timestamp": Something like a UNIX timestamp but
302+
// including local timezone offset.
303+
return $defaultDatetime->getTimestamp() + $offset;
304+
}
305+
}
306+
252307
/**
253308
* Returns either the ColumnSchema or a new instance of the related model
254309
* for the given attribute name.

0 commit comments

Comments
 (0)