diff --git a/extra/intl-extra/IntlExtension.php b/extra/intl-extra/IntlExtension.php index 955d6ec9233..f8eaa60a91e 100644 --- a/extra/intl-extra/IntlExtension.php +++ b/extra/intl-extra/IntlExtension.php @@ -370,7 +370,14 @@ public function formatNumberStyle(string $style, $number, array $attrs = [], str public function formatDateTime(Environment $env, $date, ?string $dateFormat = 'medium', ?string $timeFormat = 'medium', string $pattern = '', $timezone = null, string $calendar = 'gregorian', string $locale = null): string { $date = twig_date_converter($env, $date, $timezone); - $formatter = $this->createDateFormatter($locale, $dateFormat, $timeFormat, $pattern, $date->getTimezone(), $calendar); + + $formatterTimezone = $timezone; + if (false === $formatterTimezone) { + $formatterTimezone = $date->getTimezone(); + } elseif (\is_string($formatterTimezone)) { + $formatterTimezone = new \DateTimeZone($timezone); + } + $formatter = $this->createDateFormatter($locale, $dateFormat, $timeFormat, $pattern, $formatterTimezone, $calendar); if (false === $ret = $formatter->format($date)) { throw new RuntimeError('Unable to format the given date.'); @@ -397,7 +404,7 @@ public function formatTime(Environment $env, $date, ?string $timeFormat = 'mediu return $this->formatDateTime($env, $date, 'none', $timeFormat, $pattern, $timezone, $calendar, $locale); } - private function createDateFormatter(?string $locale, ?string $dateFormat, ?string $timeFormat, string $pattern, \DateTimeZone $timezone, string $calendar): \IntlDateFormatter + private function createDateFormatter(?string $locale, ?string $dateFormat, ?string $timeFormat, string $pattern, ?\DateTimeZone $timezone, string $calendar): \IntlDateFormatter { $dateFormats = self::availableDateFormats(); @@ -410,7 +417,10 @@ private function createDateFormatter(?string $locale, ?string $dateFormat, ?stri } if (null === $locale) { - $locale = \Locale::getDefault(); + if ($this->dateFormatterPrototype) { + $locale = $this->dateFormatterPrototype->getLocale(); + } + $locale = $locale ?: \Locale::getDefault(); } $calendar = 'gregorian' === $calendar ? \IntlDateFormatter::GREGORIAN : \IntlDateFormatter::TRADITIONAL; @@ -421,12 +431,14 @@ private function createDateFormatter(?string $locale, ?string $dateFormat, ?stri if ($this->dateFormatterPrototype) { $dateFormatValue = $dateFormatValue ?: $this->dateFormatterPrototype->getDateType(); $timeFormatValue = $timeFormatValue ?: $this->dateFormatterPrototype->getTimeType(); - $timezone = $timezone ?: $this->dateFormatterPrototype->getTimeType(); + $timezone = $timezone ?: $this->dateFormatterPrototype->getTimeZone()->toDateTimeZone(); $calendar = $calendar ?: $this->dateFormatterPrototype->getCalendar(); $pattern = $pattern ?: $this->dateFormatterPrototype->getPattern(); } - $hash = $locale.'|'.$dateFormatValue.'|'.$timeFormatValue.'|'.$timezone->getName().'|'.$calendar.'|'.$pattern; + $timezoneName = $timezone ? $timezone->getName() : '(none)'; + + $hash = $locale.'|'.$dateFormatValue.'|'.$timeFormatValue.'|'.$timezoneName.'|'.$calendar.'|'.$pattern; if (!isset($this->dateFormatters[$hash])) { $this->dateFormatters[$hash] = new \IntlDateFormatter($locale, $dateFormatValue, $timeFormatValue, $timezone, $calendar, $pattern); diff --git a/extra/intl-extra/Tests/IntlExtensionTest.php b/extra/intl-extra/Tests/IntlExtensionTest.php index f2637620693..a05f796f914 100644 --- a/extra/intl-extra/Tests/IntlExtensionTest.php +++ b/extra/intl-extra/Tests/IntlExtensionTest.php @@ -12,17 +12,56 @@ namespace Twig\Extra\Intl\Tests; use PHPUnit\Framework\TestCase; +use Twig\Environment; use Twig\Extra\Intl\IntlExtension; +use Twig\Loader\ArrayLoader; class IntlExtensionTest extends TestCase { + public function testFormatterWithoutProto() + { + $ext = new IntlExtension(); + $env = new Environment(new ArrayLoader()); + + $this->assertSame('12.346', $ext->formatNumber('12.3456')); + $this->assertSame( + 'Feb 20, 2020, 1:37:00 PM', + $ext->formatDateTime($env, new \DateTime('2020-02-20T13:37:00+00:00')) + ); + } + public function testFormatterProto() { - $dateFormatterProto = new \IntlDateFormatter('fr', \IntlDateFormatter::FULL, \IntlDateFormatter::FULL); + $dateFormatterProto = new \IntlDateFormatter('fr', \IntlDateFormatter::FULL, \IntlDateFormatter::FULL, new \DateTimeZone('Europe/Paris')); $numberFormatterProto = new \NumberFormatter('fr', \NumberFormatter::DECIMAL); $numberFormatterProto->setTextAttribute(\NumberFormatter::POSITIVE_PREFIX, '++'); $numberFormatterProto->setAttribute(\NumberFormatter::FRACTION_DIGITS, 1); $ext = new IntlExtension($dateFormatterProto, $numberFormatterProto); + $env = new Environment(new ArrayLoader()); + $this->assertSame('++12,3', $ext->formatNumber('12.3456')); + $this->assertSame( + 'jeudi 20 février 2020 à 14:37:00 heure normale d’Europe centrale', + $ext->formatDateTime($env, new \DateTime('2020-02-20T13:37:00+00:00')) + ); + } + + public function testFormatterOverridenProto() + { + $dateFormatterProto = new \IntlDateFormatter('fr', \IntlDateFormatter::FULL, \IntlDateFormatter::FULL, new \DateTimeZone('Europe/Paris')); + $numberFormatterProto = new \NumberFormatter('fr', \NumberFormatter::DECIMAL); + $numberFormatterProto->setTextAttribute(\NumberFormatter::POSITIVE_PREFIX, '++'); + $numberFormatterProto->setAttribute(\NumberFormatter::FRACTION_DIGITS, 1); + $ext = new IntlExtension($dateFormatterProto, $numberFormatterProto); + $env = new Environment(new ArrayLoader()); + + $this->assertSame( + 'twelve point three', + $ext->formatNumber('12.3456', [], 'spellout', 'default', 'en_US') + ); + $this->assertSame( + '2020-02-20 13:37:00', + $ext->formatDateTime($env, new \DateTime('2020-02-20T13:37:00+00:00'), 'short', 'short', 'yyyy-MM-dd HH:mm:ss', 'UTC', 'gregorian', 'en_US') + ); } }