mirror of
https://github.com/yiisoft/yii2.git
synced 2025-11-23 10:09:40 +08:00
@@ -88,6 +88,8 @@ See http://site.icu-project.org/ for the format.
|
|||||||
and now in human readable form.
|
and now in human readable form.
|
||||||
|
|
||||||
|
|
||||||
|
The input value for date and time formatting is assumed to be in UTC unless a timezone is explicitly given.
|
||||||
|
|
||||||
Formatting Numbers
|
Formatting Numbers
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ Yii Framework 2 Change Log
|
|||||||
2.0.0 under development
|
2.0.0 under development
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
|
- Bug: Date and time formatting now assumes UTC as the timezone for input dates unless a timezone is explicitly given (cebe)
|
||||||
- Enh #4275: Added `removeChildren()` to `yii\rbac\ManagerInterface` and implementations (samdark)
|
- Enh #4275: Added `removeChildren()` to `yii\rbac\ManagerInterface` and implementations (samdark)
|
||||||
|
|
||||||
|
|
||||||
@@ -623,6 +624,7 @@ Yii Framework 2 Change Log
|
|||||||
- New: Added various authentication methods, including `HttpBasicAuth`, `HttpBearerAuth`, `QueryParamAuth`, and `CompositeAuth` (qiangxue)
|
- New: Added various authentication methods, including `HttpBasicAuth`, `HttpBearerAuth`, `QueryParamAuth`, and `CompositeAuth` (qiangxue)
|
||||||
- New: Added `HtmlResponseFormatter` and `JsonResponseFormatter` (qiangxue)
|
- New: Added `HtmlResponseFormatter` and `JsonResponseFormatter` (qiangxue)
|
||||||
|
|
||||||
|
|
||||||
2.0.0-alpha, December 1, 2013
|
2.0.0-alpha, December 1, 2013
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,12 @@ Upgrade from Yii 2.0 RC
|
|||||||
|
|
||||||
* If you've implemented `yii\rbac\ManagerInterface` you need to add implementation for new method `removeChildren()`.
|
* If you've implemented `yii\rbac\ManagerInterface` you need to add implementation for new method `removeChildren()`.
|
||||||
|
|
||||||
|
* The input dates for datetime formatting are now assumed to be in UTC unless a timezone is explicitly given.
|
||||||
|
Before, the timezone assumed for input dates was the default timezone set by PHP which is the same as `Yii::$app->timeZone`.
|
||||||
|
This causes trouble because the formatter uses `Yii::$app->timeZone` as the default values for output so no timezone conversion
|
||||||
|
was possible. If your timestamps are stored in the database without a timezone identifier you have to ensure they are in UTC or
|
||||||
|
add a timezone identifier explicitly.
|
||||||
|
|
||||||
|
|
||||||
Upgrade from Yii 2.0 Beta
|
Upgrade from Yii 2.0 Beta
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
namespace yii\i18n;
|
namespace yii\i18n;
|
||||||
|
|
||||||
use DateTime;
|
use DateTime;
|
||||||
|
use DateTimeZone;
|
||||||
use IntlDateFormatter;
|
use IntlDateFormatter;
|
||||||
use NumberFormatter;
|
use NumberFormatter;
|
||||||
use Yii;
|
use Yii;
|
||||||
@@ -66,6 +67,9 @@ class Formatter extends Component
|
|||||||
* e.g. `UTC`, `Europe/Berlin` or `America/Chicago`.
|
* 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 timezones.
|
||||||
* If this property is not set, [[\yii\base\Application::timeZone]] will be used.
|
* 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.
|
||||||
*/
|
*/
|
||||||
public $timeZone;
|
public $timeZone;
|
||||||
/**
|
/**
|
||||||
@@ -387,8 +391,9 @@ class Formatter extends Component
|
|||||||
* types of value are supported:
|
* types of value are supported:
|
||||||
*
|
*
|
||||||
* - an integer representing a UNIX timestamp
|
* - an integer representing a UNIX timestamp
|
||||||
* - a string that can be parsed into a UNIX timestamp via `strtotime()`
|
* - a string that can be [parsed to create a DateTime object](http://php.net/manual/en/datetime.formats.php).
|
||||||
* - a PHP DateTime object
|
* The timestamp is assumed to be in UTC unless a timezone 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.
|
* @param string $format the format used to convert the value into a date string.
|
||||||
* If null, [[dateFormat]] will be used.
|
* If null, [[dateFormat]] will be used.
|
||||||
@@ -399,9 +404,9 @@ class Formatter extends Component
|
|||||||
* Alternatively this can be a string prefixed with `php:` representing a format that can be recognized by the
|
* Alternatively this can be a string prefixed with `php:` representing a format that can be recognized by the
|
||||||
* PHP [date()](http://php.net/manual/de/function.date.php)-function.
|
* PHP [date()](http://php.net/manual/de/function.date.php)-function.
|
||||||
*
|
*
|
||||||
|
* @return string the formatted result.
|
||||||
* @throws InvalidParamException if the input value can not be evaluated as a date value.
|
* @throws InvalidParamException if the input value can not be evaluated as a date value.
|
||||||
* @throws InvalidConfigException if the date format is invalid.
|
* @throws InvalidConfigException if the date format is invalid.
|
||||||
* @return string the formatted result.
|
|
||||||
* @see dateFormat
|
* @see dateFormat
|
||||||
*/
|
*/
|
||||||
public function asDate($value, $format = null)
|
public function asDate($value, $format = null)
|
||||||
@@ -418,8 +423,9 @@ class Formatter extends Component
|
|||||||
* types of value are supported:
|
* types of value are supported:
|
||||||
*
|
*
|
||||||
* - an integer representing a UNIX timestamp
|
* - an integer representing a UNIX timestamp
|
||||||
* - a string that can be parsed into a UNIX timestamp via `strtotime()`
|
* - a string that can be [parsed to create a DateTime object](http://php.net/manual/en/datetime.formats.php).
|
||||||
* - a PHP DateTime object
|
* The timestamp is assumed to be in UTC unless a timezone 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.
|
* @param string $format the format used to convert the value into a date string.
|
||||||
* If null, [[timeFormat]] will be used.
|
* If null, [[timeFormat]] will be used.
|
||||||
@@ -430,9 +436,9 @@ class Formatter extends Component
|
|||||||
* Alternatively this can be a string prefixed with `php:` representing a format that can be recognized by the
|
* Alternatively this can be a string prefixed with `php:` representing a format that can be recognized by the
|
||||||
* PHP [date()](http://php.net/manual/de/function.date.php)-function.
|
* PHP [date()](http://php.net/manual/de/function.date.php)-function.
|
||||||
*
|
*
|
||||||
|
* @return string the formatted result.
|
||||||
* @throws InvalidParamException if the input value can not be evaluated as a date value.
|
* @throws InvalidParamException if the input value can not be evaluated as a date value.
|
||||||
* @throws InvalidConfigException if the date format is invalid.
|
* @throws InvalidConfigException if the date format is invalid.
|
||||||
* @return string the formatted result.
|
|
||||||
* @see timeFormat
|
* @see timeFormat
|
||||||
*/
|
*/
|
||||||
public function asTime($value, $format = null)
|
public function asTime($value, $format = null)
|
||||||
@@ -449,8 +455,9 @@ class Formatter extends Component
|
|||||||
* types of value are supported:
|
* types of value are supported:
|
||||||
*
|
*
|
||||||
* - an integer representing a UNIX timestamp
|
* - an integer representing a UNIX timestamp
|
||||||
* - a string that can be parsed into a UNIX timestamp via `strtotime()`
|
* - a string that can be [parsed to create a DateTime object](http://php.net/manual/en/datetime.formats.php).
|
||||||
* - a PHP DateTime object
|
* The timestamp is assumed to be in UTC unless a timezone 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.
|
* @param string $format the format used to convert the value into a date string.
|
||||||
* If null, [[dateFormat]] will be used.
|
* If null, [[dateFormat]] will be used.
|
||||||
@@ -461,9 +468,9 @@ class Formatter extends Component
|
|||||||
* Alternatively this can be a string prefixed with `php:` representing a format that can be recognized by the
|
* Alternatively this can be a string prefixed with `php:` representing a format that can be recognized by the
|
||||||
* PHP [date()](http://php.net/manual/de/function.date.php)-function.
|
* PHP [date()](http://php.net/manual/de/function.date.php)-function.
|
||||||
*
|
*
|
||||||
|
* @return string the formatted result.
|
||||||
* @throws InvalidParamException if the input value can not be evaluated as a date value.
|
* @throws InvalidParamException if the input value can not be evaluated as a date value.
|
||||||
* @throws InvalidConfigException if the date format is invalid.
|
* @throws InvalidConfigException if the date format is invalid.
|
||||||
* @return string the formatted result.
|
|
||||||
* @see datetimeFormat
|
* @see datetimeFormat
|
||||||
*/
|
*/
|
||||||
public function asDatetime($value, $format = null)
|
public function asDatetime($value, $format = null)
|
||||||
@@ -485,7 +492,14 @@ class Formatter extends Component
|
|||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param integer $value normalized datetime value
|
* @param integer|string|DateTime $value the value to be formatted. The following
|
||||||
|
* types of value are supported:
|
||||||
|
*
|
||||||
|
* - 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.
|
||||||
|
* - 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.
|
* @param string $format the format used to convert the value into a date string.
|
||||||
* @param string $type 'date', 'time', or 'datetime'.
|
* @param string $type 'date', 'time', or 'datetime'.
|
||||||
* @throws InvalidConfigException if the date format is invalid.
|
* @throws InvalidConfigException if the date format is invalid.
|
||||||
@@ -524,7 +538,7 @@ class Formatter extends Component
|
|||||||
$format = FormatConverter::convertDateIcuToPhp($format, $type, $this->locale);
|
$format = FormatConverter::convertDateIcuToPhp($format, $type, $this->locale);
|
||||||
}
|
}
|
||||||
if ($this->timeZone != null) {
|
if ($this->timeZone != null) {
|
||||||
$timestamp->setTimezone(new \DateTimeZone($this->timeZone));
|
$timestamp->setTimezone(new DateTimeZone($this->timeZone));
|
||||||
}
|
}
|
||||||
return $timestamp->format($format);
|
return $timestamp->format($format);
|
||||||
}
|
}
|
||||||
@@ -533,7 +547,14 @@ class Formatter extends Component
|
|||||||
/**
|
/**
|
||||||
* Normalizes the given datetime value as a DateTime object that can be taken by various date/time formatting methods.
|
* Normalizes the given datetime value as a DateTime object that can be taken by various date/time formatting methods.
|
||||||
*
|
*
|
||||||
* @param mixed $value the datetime value to be normalized.
|
* @param integer|string|DateTime $value the datetime value to be normalized. The following
|
||||||
|
* types of value are supported:
|
||||||
|
*
|
||||||
|
* - 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.
|
||||||
|
* - a PHP [DateTime](http://php.net/manual/en/class.datetime.php) object
|
||||||
|
*
|
||||||
* @return DateTime the normalized datetime value
|
* @return DateTime the normalized datetime value
|
||||||
* @throws InvalidParamException if the input value can not be evaluated as a date value.
|
* @throws InvalidParamException if the input value can not be evaluated as a date value.
|
||||||
*/
|
*/
|
||||||
@@ -548,17 +569,17 @@ class Formatter extends Component
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (is_numeric($value)) { // process as unix timestamp
|
if (is_numeric($value)) { // process as unix timestamp
|
||||||
if (($timestamp = DateTime::createFromFormat('U', $value)) === false) {
|
if (($timestamp = DateTime::createFromFormat('U', $value, new DateTimeZone('UTC'))) === false) {
|
||||||
throw new InvalidParamException("Failed to parse '$value' as a UNIX timestamp.");
|
throw new InvalidParamException("Failed to parse '$value' as a UNIX timestamp.");
|
||||||
}
|
}
|
||||||
return $timestamp;
|
return $timestamp;
|
||||||
} elseif (($timestamp = DateTime::createFromFormat('Y-m-d', $value)) !== false) { // try Y-m-d format
|
} elseif (($timestamp = DateTime::createFromFormat('Y-m-d', $value, new DateTimeZone('UTC'))) !== false) { // try Y-m-d format (support invalid dates like 2012-13-01)
|
||||||
return $timestamp;
|
return $timestamp;
|
||||||
} elseif (($timestamp = DateTime::createFromFormat('Y-m-d H:i:s', $value)) !== false) { // try Y-m-d H:i:s format
|
} 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)
|
||||||
return $timestamp;
|
return $timestamp;
|
||||||
}
|
}
|
||||||
// finally try to create a DateTime object with the value
|
// finally try to create a DateTime object with the value
|
||||||
$timestamp = new DateTime($value);
|
$timestamp = new DateTime($value, new DateTimeZone('UTC'));
|
||||||
return $timestamp;
|
return $timestamp;
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
throw new InvalidParamException("'$value' is not a valid date time value: " . $e->getMessage()
|
throw new InvalidParamException("'$value' is not a valid date time value: " . $e->getMessage()
|
||||||
@@ -623,7 +644,7 @@ class Formatter extends Component
|
|||||||
return $this->nullDisplay;
|
return $this->nullDisplay;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$timezone = new \DateTimeZone($this->timeZone);
|
$timezone = new DateTimeZone($this->timeZone);
|
||||||
|
|
||||||
if ($referenceTime === null) {
|
if ($referenceTime === null) {
|
||||||
$dateNow = new DateTime('now', $timezone);
|
$dateNow = new DateTime('now', $timezone);
|
||||||
|
|||||||
@@ -483,6 +483,90 @@ class FormatterTest extends TestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function provideTimezones()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['UTC'],
|
||||||
|
['Europe/Berlin'],
|
||||||
|
['America/Jamaica'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* provide default timezones times input date value
|
||||||
|
*/
|
||||||
|
public function provideTimesAndTz()
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
foreach($this->provideTimezones() as $tz) {
|
||||||
|
$result[] = [$tz[0], 1407674460, 1388580060];
|
||||||
|
$result[] = [$tz[0], '2014-08-10 12:41:00', '2014-01-01 12:41:00'];
|
||||||
|
$result[] = [$tz[0], '2014-08-10 12:41:00 UTC', '2014-01-01 12:41:00 UTC'];
|
||||||
|
$result[] = [$tz[0], '2014-08-10 14:41:00 Europe/Berlin', '2014-01-01 13:41:00 Europe/Berlin'];
|
||||||
|
$result[] = [$tz[0], '2014-08-10 14:41:00 CEST', '2014-01-01 13:41:00 CET'];
|
||||||
|
$result[] = [$tz[0], '2014-08-10 14:41:00+0200', '2014-01-01 13:41:00+0100'];
|
||||||
|
$result[] = [$tz[0], '2014-08-10 14:41:00+02:00', '2014-01-01 13:41:00+01:00'];
|
||||||
|
$result[] = [$tz[0], '2014-08-10 14:41:00 +0200', '2014-01-01 13:41:00 +0100'];
|
||||||
|
$result[] = [$tz[0], '2014-08-10 14:41:00 +02:00', '2014-01-01 13:41:00 +01:00'];
|
||||||
|
$result[] = [$tz[0], '2014-08-10T14:41:00+02:00', '2014-01-01T13:41:00+01:00']; // ISO 8601
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test timezones with input date and time in other timezones
|
||||||
|
* @dataProvider provideTimesAndTz
|
||||||
|
*/
|
||||||
|
public function testIntlTimezoneInput($defaultTz, $inputTimeDst, $inputTimeNonDst)
|
||||||
|
{
|
||||||
|
$this->testTimezoneInput($defaultTz, $inputTimeDst, $inputTimeNonDst);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test timezones with input date and time in other timezones
|
||||||
|
* @dataProvider provideTimesAndTz
|
||||||
|
*/
|
||||||
|
public function testTimezoneInput($defaultTz, $inputTimeDst, $inputTimeNonDst)
|
||||||
|
{
|
||||||
|
date_default_timezone_set($defaultTz); // formatting has to be independent of the default timezone set by PHP
|
||||||
|
$this->formatter->datetimeFormat = 'yyyy-MM-dd HH:mm:ss';
|
||||||
|
$this->formatter->dateFormat = 'yyyy-MM-dd';
|
||||||
|
$this->formatter->timeFormat = 'HH:mm:ss';
|
||||||
|
|
||||||
|
// daylight saving time
|
||||||
|
$this->formatter->timeZone = 'UTC';
|
||||||
|
$this->assertSame('2014-08-10 12:41:00', $this->formatter->asDatetime($inputTimeDst));
|
||||||
|
$this->assertSame('2014-08-10', $this->formatter->asDate($inputTimeDst));
|
||||||
|
$this->assertSame('12:41:00', $this->formatter->asTime($inputTimeDst));
|
||||||
|
$this->assertSame('1407674460', $this->formatter->asTimestamp($inputTimeDst));
|
||||||
|
$this->formatter->timeZone = 'Europe/Berlin';
|
||||||
|
$this->assertSame('2014-08-10 14:41:00', $this->formatter->asDatetime($inputTimeDst));
|
||||||
|
$this->assertSame('2014-08-10', $this->formatter->asDate($inputTimeDst));
|
||||||
|
$this->assertSame('14:41:00', $this->formatter->asTime($inputTimeDst));
|
||||||
|
$this->assertSame('1407674460', $this->formatter->asTimestamp($inputTimeDst));
|
||||||
|
|
||||||
|
// non daylight saving time
|
||||||
|
$this->formatter->timeZone = 'UTC';
|
||||||
|
$this->assertSame('2014-01-01 12:41:00', $this->formatter->asDatetime($inputTimeNonDst));
|
||||||
|
$this->assertSame('2014-01-01', $this->formatter->asDate($inputTimeNonDst));
|
||||||
|
$this->assertSame('12:41:00', $this->formatter->asTime($inputTimeNonDst));
|
||||||
|
$this->assertSame('1388580060', $this->formatter->asTimestamp($inputTimeNonDst));
|
||||||
|
$this->formatter->timeZone = 'Europe/Berlin';
|
||||||
|
$this->assertSame('2014-01-01 13:41:00', $this->formatter->asDatetime($inputTimeNonDst));
|
||||||
|
$this->assertSame('2014-01-01', $this->formatter->asDate($inputTimeNonDst));
|
||||||
|
$this->assertSame('13:41:00', $this->formatter->asTime($inputTimeNonDst));
|
||||||
|
$this->assertSame('1388580060', $this->formatter->asTimestamp($inputTimeNonDst));
|
||||||
|
|
||||||
|
// tests for relative time
|
||||||
|
if ($inputTimeDst !== 1407674460) {
|
||||||
|
$this->assertSame('3 hours ago', $this->formatter->asRelativeTime($inputTimeDst, $relativeTime = str_replace(['14:41', '12:41'], ['17:41', '15:41'], $inputTimeDst)));
|
||||||
|
$this->assertSame('in 3 hours', $this->formatter->asRelativeTime($relativeTime, $inputTimeDst));
|
||||||
|
$this->assertSame('3 hours ago', $this->formatter->asRelativeTime($inputTimeNonDst, $relativeTime = str_replace(['13:41', '12:41'], ['16:41', '15:41'], $inputTimeNonDst)));
|
||||||
|
$this->assertSame('in 3 hours', $this->formatter->asRelativeTime($relativeTime, $inputTimeNonDst));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// number format
|
// number format
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user