From 6e7dc26b38021cb68413d8e60c51a0b7411a4e3d Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Tue, 2 Dec 2014 04:23:26 +0100 Subject: [PATCH] added support for DateTimeImmutable to Formatter fixes #5503 --- framework/CHANGELOG.md | 1 + framework/i18n/Formatter.php | 10 +++++- .../unit/framework/i18n/FormatterDateTest.php | 32 +++++++++++++++++-- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 1a0b234106..ad4f396b7c 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -58,6 +58,7 @@ Yii Framework 2 Change Log - Enh #5223: Query builder now supports selecting sub-queries as columns (qiangxue) - Enh #5367: Added `yii\grid\DataColumn::encodeLabel` (SDKiller) - Enh #5480: Added defensive code to `yii\web\User::getIdentity()` to avoid potential infinite recursion (qiangxue) +- Enh #5503: Added support for `DateTimeImmutable` to Formatter (olegtsvetkov, cebe) - Enh #5587: `json_encode` is now used with `JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE` where it makes sense, also it is now default for `Json::encode()` (samdark) - Enh #5600: Allow configuring debug panels in `yii\debug\Module::panels` as panel class name strings (qiangxue) diff --git a/framework/i18n/Formatter.php b/framework/i18n/Formatter.php index 63d4b8fc9b..bf44c87af8 100644 --- a/framework/i18n/Formatter.php +++ b/framework/i18n/Formatter.php @@ -561,6 +561,10 @@ class Formatter extends Component if ($formatter === null) { throw new InvalidConfigException(intl_get_error_message()); } + // make IntlDateFormatter work with DateTimeImmutable + if ($timestamp instanceof \DateTimeImmutable) { + $timestamp = new DateTime($timestamp->format(DateTime::ISO8601), $timestamp->getTimezone()); + } return $formatter->format($timestamp); } else { if (strncmp($format, 'php:', 4) === 0) { @@ -569,7 +573,11 @@ class Formatter extends Component $format = FormatConverter::convertDateIcuToPhp($format, $type, $this->locale); } if ($timeZone != null) { - $timestamp->setTimezone(new DateTimeZone($timeZone)); + if ($timestamp instanceof \DateTimeImmutable) { + $timestamp = $timestamp->setTimezone(new DateTimeZone($timeZone)); + } else { + $timestamp->setTimezone(new DateTimeZone($timeZone)); + } } return $timestamp->format($format); } diff --git a/tests/unit/framework/i18n/FormatterDateTest.php b/tests/unit/framework/i18n/FormatterDateTest.php index 8a80f284c8..8dd41690e9 100644 --- a/tests/unit/framework/i18n/FormatterDateTest.php +++ b/tests/unit/framework/i18n/FormatterDateTest.php @@ -70,6 +70,15 @@ class FormatterDateTest extends TestCase $this->assertSame(date('n/j/y', $value->getTimestamp()), $this->formatter->asDate($value, 'short')); $this->assertSame(date('F j, Y', $value->getTimestamp()), $this->formatter->asDate($value, 'long')); + if (version_compare(PHP_VERSION, '5.5.0', '>=')) { + $value = new \DateTimeImmutable(); + $this->assertSame(date('M j, Y', $value->getTimestamp()), $this->formatter->asDate($value)); + $this->assertSame(date('Y/m/d', $value->getTimestamp()), $this->formatter->asDate($value, 'php:Y/m/d')); + $this->assertSame(date('m/d/Y', $value->getTimestamp()), $this->formatter->asDate($value, 'MM/dd/yyyy')); + $this->assertSame(date('n/j/y', $value->getTimestamp()), $this->formatter->asDate($value, 'short')); + $this->assertSame(date('F j, Y', $value->getTimestamp()), $this->formatter->asDate($value, 'long')); + } + // empty input $this->assertSame('Jan 1, 1970', $this->formatter->asDate('')); $this->assertSame('Jan 1, 1970', $this->formatter->asDate(0)); @@ -100,6 +109,12 @@ class FormatterDateTest extends TestCase $this->assertSame(date('g:i:s A', $value->getTimestamp()), $this->formatter->asTime($value)); $this->assertSame(date('h:i:s A', $value->getTimestamp()), $this->formatter->asTime($value, 'php:h:i:s A')); + if (version_compare(PHP_VERSION, '5.5.0', '>=')) { + $value = new \DateTimeImmutable(); + $this->assertSame(date('g:i:s A', $value->getTimestamp()), $this->formatter->asTime($value)); + $this->assertSame(date('h:i:s A', $value->getTimestamp()), $this->formatter->asTime($value, 'php:h:i:s A')); + } + // empty input $this->assertSame('12:00:00 AM', $this->formatter->asTime('')); $this->assertSame('12:00:00 AM', $this->formatter->asTime(0)); @@ -129,6 +144,12 @@ class FormatterDateTest extends TestCase $this->assertSame(date('M j, Y g:i:s A', $value->getTimestamp()), $this->formatter->asDatetime($value)); $this->assertSame(date('Y/m/d h:i:s A', $value->getTimestamp()), $this->formatter->asDatetime($value, 'php:Y/m/d h:i:s A')); + if (version_compare(PHP_VERSION, '5.5.0', '>=')) { + $value = new \DateTimeImmutable(); + $this->assertSame(date('M j, Y g:i:s A', $value->getTimestamp()), $this->formatter->asDatetime($value)); + $this->assertSame(date('Y/m/d h:i:s A', $value->getTimestamp()), $this->formatter->asDatetime($value, 'php:Y/m/d h:i:s A')); + } + // empty input $this->assertSame('Jan 1, 1970 12:00:00 AM', $this->formatter->asDatetime('')); $this->assertSame('Jan 1, 1970 12:00:00 AM', $this->formatter->asDatetime(0)); @@ -338,7 +359,6 @@ class FormatterDateTest extends TestCase public function dateInputs() { return [ -// ['2015-01-01 00:00:00', '2014-13-01'], // TODO evals to current time on that date ['2015-01-01 00:00:00', '2014-13-01 00:00:00'], [false, 'asdfg', 'yii\base\InvalidParamException'], // [(string)strtotime('now'), 'now'], // fails randomly @@ -381,6 +401,8 @@ class FormatterDateTest extends TestCase */ public function provideTimesAndTz() { + $utc = new \DateTimeZone('UTC'); + $berlin = new \DateTimeZone('Europe/Berlin'); $result = []; foreach($this->provideTimezones() as $tz) { $result[] = [$tz[0], 1407674460, 1388580060]; @@ -393,6 +415,12 @@ class FormatterDateTest extends TestCase $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 + $result[] = [$tz[0], new DateTime('2014-08-10 12:41:00', $utc), new DateTime('2014-01-01 12:41:00', $utc)]; + $result[] = [$tz[0], new DateTime('2014-08-10 14:41:00', $berlin), new DateTime('2014-01-01 13:41:00', $berlin)]; + if (version_compare(PHP_VERSION, '5.5.0', '>=')) { + $result[] = [$tz[0], new \DateTimeImmutable('2014-08-10 12:41:00', $utc), new \DateTimeImmutable('2014-01-01 12:41:00', $utc)]; + $result[] = [$tz[0], new \DateTimeImmutable('2014-08-10 14:41:00', $berlin), new \DateTimeImmutable('2014-01-01 13:41:00', $berlin)]; + } } return $result; } @@ -442,7 +470,7 @@ class FormatterDateTest extends TestCase $this->assertSame('1388580060', $this->formatter->asTimestamp($inputTimeNonDst)); // tests for relative time - if ($inputTimeDst !== 1407674460) { + if ($inputTimeDst !== 1407674460 && !is_object($inputTimeDst)) { $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)));