Commit 8039026a by Carsten Brandt

added Formatter::defaultTimeZone to allow non UTC-values in DB

fixes #5683
parent db82518d
......@@ -124,6 +124,9 @@ echo Yii::$app->formatter->asTime('2014-10-06 12:41:00'); // 14:41:00
echo Yii::$app->formatter->asTime('2014-10-06 14:41:00 CEST'); // 14:41:00
```
Since version 2.0.1 it is also possible to configure the time zone that is assumed for timestamps that do not include a time zone
identifier like the second example in the code above. You can set [[yii\i18n\Formatter::defaultTimeZone]] to the time zone you use for data storage.
> Note: As time zones are subject to rules made by the governments around the world and may change frequently, it is
> likely that you do not have the latest information in the time zone database installed on your system.
> You may refer to the [ICU manual](http://userguide.icu-project.org/datetime/timezone#TOC-Updating-the-Time-Zone-Data)
......
......@@ -43,6 +43,7 @@ Yii Framework 2 Change Log
- Enh #5600: Allow configuring debug panels in `yii\debug\Module::panels` as panel class name strings (qiangxue)
- Enh #5613: Added `--overwrite` option to Gii console command to support overwriting all files (motin, qiangxue)
- Enh #5646: Call `yii\base\ErrorHandler::unregister()` instead of `restore_*_handlers` directly (aivus)
- Enh #5683: Added `yii\i18n\Formatter::defaultTimeZone` for specifying the default time zone to use for datetime values stored in the database (cebe)
- Enh #5688: Added optional `$formName` to `Model::loadMultiple()` to support customizing form name directly (qiangxue)
- Enh #5735: Added `yii\bootstrap\Tabs::renderTabContent` to support manually rendering tab contents (RomeroMsk)
- Enh #5770: Added more PHP error names for `ErrorException` (mongosoft)
......
......@@ -64,17 +64,27 @@ class Formatter extends Component
*/
public $locale;
/**
* @var string the timezone to use for formatting time and date values.
* @var string the time zone to use for formatting time and date values.
*
* This can be any value that may be passed to [date_default_timezone_set()](http://www.php.net/manual/en/function.date-default-timezone-set.php)
* e.g. `UTC`, `Europe/Berlin` or `America/Chicago`.
* Refer to the [php manual](http://www.php.net/manual/en/timezones.php) for available timezones.
* Refer to the [php manual](http://www.php.net/manual/en/timezones.php) for available time zones.
* If this property is not set, [[\yii\base\Application::timeZone]] will be used.
*
* Note that the input timezone is assumed to be UTC always if no timezone is included in the input date value.
* Make sure to store datetime values in UTC in your database.
* Note that the default time zone for input data is assumed to be UTC by default if no time zone is included in the input date value.
* If you store your data in a different time zone in the database, you have to adjust [[defaultTimeZone]] accordingly.
*/
public $timeZone;
/**
* @var string the time zone that is assumed for input values if they do not include a time zone explicitly.
*
* The value must be a valid time zone identifier, e.g. `UTC`, `Europe/Berlin` or `America/Chicago`.
* Please refer to the [php manual](http://www.php.net/manual/en/timezones.php) for available time zones.
*
* It defaults to `UTC` so you only have to adjust this value if you store datetime values in another time zone in your database.
*/
public $defaultTimeZone = 'UTC';
/**
* @var string the default format string to be used to format a [[asDate()|date]].
* This can be "short", "medium", "long", or "full", which represents a preset format of different lengths.
*
......@@ -402,7 +412,7 @@ class Formatter extends Component
*
* - an integer representing a UNIX timestamp
* - a string that can be [parsed to create a DateTime object](http://php.net/manual/en/datetime.formats.php).
* The timestamp is assumed to be in UTC unless a timezone is explicitly given.
* The timestamp is assumed to be in [[defaultTimeZone]] unless a time zone is explicitly given.
* - a PHP [DateTime](http://php.net/manual/en/class.datetime.php) object
*
* @param string $format the format used to convert the value into a date string.
......@@ -434,7 +444,7 @@ class Formatter extends Component
*
* - an integer representing a UNIX timestamp
* - a string that can be [parsed to create a DateTime object](http://php.net/manual/en/datetime.formats.php).
* The timestamp is assumed to be in UTC unless a timezone is explicitly given.
* The timestamp is assumed to be in [[defaultTimeZone]] unless a time zone is explicitly given.
* - a PHP [DateTime](http://php.net/manual/en/class.datetime.php) object
*
* @param string $format the format used to convert the value into a date string.
......@@ -466,7 +476,7 @@ class Formatter extends Component
*
* - an integer representing a UNIX timestamp
* - a string that can be [parsed to create a DateTime object](http://php.net/manual/en/datetime.formats.php).
* The timestamp is assumed to be in UTC unless a timezone is explicitly given.
* The timestamp is assumed to be in [[defaultTimeZone]] unless a time zone is explicitly given.
* - a PHP [DateTime](http://php.net/manual/en/class.datetime.php) object
*
* @param string $format the format used to convert the value into a date string.
......@@ -507,7 +517,7 @@ class Formatter extends Component
*
* - an integer representing a UNIX timestamp
* - a string that can be [parsed to create a DateTime object](http://php.net/manual/en/datetime.formats.php).
* The timestamp is assumed to be in UTC unless a timezone is explicitly given.
* The timestamp is assumed to be in [[defaultTimeZone]] unless a time zone is explicitly given.
* - a PHP [DateTime](http://php.net/manual/en/class.datetime.php) object
*
* @param string $format the format used to convert the value into a date string.
......@@ -562,7 +572,7 @@ class Formatter extends Component
*
* - an integer representing a UNIX timestamp
* - a string that can be [parsed to create a DateTime object](http://php.net/manual/en/datetime.formats.php).
* The timestamp is assumed to be in UTC unless a timezone is explicitly given.
* The timestamp is assumed to be in [[defaultTimeZone]] unless a time zone is explicitly given.
* - a PHP [DateTime](http://php.net/manual/en/class.datetime.php) object
*
* @return DateTime the normalized datetime value
......@@ -578,18 +588,18 @@ class Formatter extends Component
$value = 0;
}
try {
if (is_numeric($value)) { // process as unix timestamp
if (is_numeric($value)) { // process as unix timestamp, which is always in UTC
if (($timestamp = DateTime::createFromFormat('U', $value, new DateTimeZone('UTC'))) === false) {
throw new InvalidParamException("Failed to parse '$value' as a UNIX timestamp.");
}
return $timestamp;
} elseif (($timestamp = DateTime::createFromFormat('Y-m-d', $value, new DateTimeZone('UTC'))) !== false) { // try Y-m-d format (support invalid dates like 2012-13-01)
} elseif (($timestamp = DateTime::createFromFormat('Y-m-d', $value, new DateTimeZone($this->defaultTimeZone))) !== false) { // try Y-m-d format (support invalid dates like 2012-13-01)
return $timestamp;
} elseif (($timestamp = DateTime::createFromFormat('Y-m-d H:i:s', $value, new DateTimeZone('UTC'))) !== false) { // try Y-m-d H:i:s format (support invalid dates like 2012-13-01 12:63:12)
} elseif (($timestamp = DateTime::createFromFormat('Y-m-d H:i:s', $value, new DateTimeZone($this->defaultTimeZone))) !== false) { // try Y-m-d H:i:s format (support invalid dates like 2012-13-01 12:63:12)
return $timestamp;
}
// finally try to create a DateTime object with the value
$timestamp = new DateTime($value, new DateTimeZone('UTC'));
$timestamp = new DateTime($value, new DateTimeZone($this->defaultTimeZone));
return $timestamp;
} catch(\Exception $e) {
throw new InvalidParamException("'$value' is not a valid date time value: " . $e->getMessage()
......@@ -604,7 +614,7 @@ class Formatter extends Component
*
* - an integer representing a UNIX timestamp
* - a string that can be [parsed to create a DateTime object](http://php.net/manual/en/datetime.formats.php).
* The timestamp is assumed to be in UTC unless a timezone is explicitly given.
* The timestamp is assumed to be in [[defaultTimeZone]] unless a time zone is explicitly given.
* - a PHP [DateTime](http://php.net/manual/en/class.datetime.php) object
*
* @return string the formatted result.
......@@ -632,7 +642,7 @@ class Formatter extends Component
*
* - an integer representing a UNIX timestamp
* - a string that can be [parsed to create a DateTime object](http://php.net/manual/en/datetime.formats.php).
* The timestamp is assumed to be in UTC unless a timezone is explicitly given.
* The timestamp is assumed to be in [[defaultTimeZone]] unless a time zone is explicitly given.
* - a PHP [DateTime](http://php.net/manual/en/class.datetime.php) object
* - a PHP DateInterval object (a positive time interval will refer to the past, a negative one to the future)
*
......@@ -662,16 +672,16 @@ class Formatter extends Component
return $this->nullDisplay;
}
} else {
$timezone = new DateTimeZone($this->timeZone);
$timeZone = new DateTimeZone($this->timeZone);
if ($referenceTime === null) {
$dateNow = new DateTime('now', $timezone);
$dateNow = new DateTime('now', $timeZone);
} else {
$dateNow = $this->normalizeDatetimeValue($referenceTime);
$dateNow->setTimezone($timezone);
$dateNow->setTimezone($timeZone);
}
$dateThen = $timestamp->setTimezone($timezone);
$dateThen = $timestamp->setTimezone($timeZone);
$interval = $dateThen->diff($dateNow);
}
......
......@@ -582,6 +582,53 @@ class FormatterTest extends TestCase
}
/**
* Test timezones with input date and time in other timezones
*/
public function testTimezoneInputNonDefault()
{
$this->formatter->datetimeFormat = 'yyyy-MM-dd HH:mm:ss';
$this->formatter->dateFormat = 'yyyy-MM-dd';
$this->formatter->timeFormat = 'HH:mm:ss';
$this->formatter->timeZone = 'UTC';
$this->formatter->defaultTimeZone = 'UTC';
$this->assertSame('2014-08-10 12:41:00', $this->formatter->asDatetime('2014-08-10 12:41:00'));
$this->assertSame('2014-08-10', $this->formatter->asDate('2014-08-10 12:41:00'));
$this->assertSame('12:41:00', $this->formatter->asTime('2014-08-10 12:41:00'));
$this->assertSame('1407674460', $this->formatter->asTimestamp('2014-08-10 12:41:00'));
$this->assertSame('2014-08-10 10:41:00', $this->formatter->asDatetime('2014-08-10 12:41:00 Europe/Berlin'));
$this->assertSame('2014-08-10', $this->formatter->asDate('2014-08-10 12:41:00 Europe/Berlin'));
$this->assertSame('10:41:00', $this->formatter->asTime('2014-08-10 12:41:00 Europe/Berlin'));
$this->assertSame('1407674460', $this->formatter->asTimestamp('2014-08-10 14:41:00 Europe/Berlin'));
$this->formatter->timeZone = 'Europe/Berlin';
$this->formatter->defaultTimeZone = 'Europe/Berlin';
$this->assertSame('2014-08-10 12:41:00', $this->formatter->asDatetime('2014-08-10 12:41:00'));
$this->assertSame('2014-08-10', $this->formatter->asDate('2014-08-10 12:41:00'));
$this->assertSame('12:41:00', $this->formatter->asTime('2014-08-10 12:41:00'));
$this->assertSame('1407674460', $this->formatter->asTimestamp('2014-08-10 14:41:00'));
$this->assertSame('2014-08-10 12:41:00', $this->formatter->asDatetime('2014-08-10 12:41:00 Europe/Berlin'));
$this->assertSame('2014-08-10', $this->formatter->asDate('2014-08-10 12:41:00 Europe/Berlin'));
$this->assertSame('12:41:00', $this->formatter->asTime('2014-08-10 12:41:00 Europe/Berlin'));
$this->assertSame('1407674460', $this->formatter->asTimestamp('2014-08-10 14:41:00 Europe/Berlin'));
$this->formatter->timeZone = 'UTC';
$this->formatter->defaultTimeZone = 'Europe/Berlin';
$this->assertSame('2014-08-10 10:41:00', $this->formatter->asDatetime('2014-08-10 12:41:00'));
$this->assertSame('2014-08-10', $this->formatter->asDate('2014-08-10 12:41:00'));
$this->assertSame('10:41:00', $this->formatter->asTime('2014-08-10 12:41:00'));
$this->assertSame('1407674460', $this->formatter->asTimestamp('2014-08-10 14:41:00'));
$this->assertSame('2014-08-10 12:41:00', $this->formatter->asDatetime('2014-08-10 12:41:00 UTC'));
$this->assertSame('2014-08-10', $this->formatter->asDate('2014-08-10 12:41:00 UTC'));
$this->assertSame('12:41:00', $this->formatter->asTime('2014-08-10 12:41:00 UTC'));
$this->assertSame('1407674460', $this->formatter->asTimestamp('2014-08-10 12:41:00 UTC'));
}
// number format
/**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment