Skip to content

Commit

Permalink
[BUGFIX] Mitigate locale C in DateFormatter wrapping class
Browse files Browse the repository at this point in the history
Since PHP 8.3.0RC3 [1] the `\IntlDateFormatter` throws a
`\IntlException` exception with the message:

    datefmt_create: invalid locale: U_ILLEGAL_ARGUMENT_ERROR

if an invalid locale is passed to the constructor. The value `C`
is considered as a non-valid locale, albeit it may be set.

This change introduces a fallback to `en-US` for the two methods
of the `\TYPO3\CMS\Core\Localization\DateFormatter` wrapping class,
if `C` is passed as locale.

`en-US` has been chosen as fallback because the TYPO3 locale class
`\TYPO3\CMS\Core\Localization\Locale` uses the same as fallback if
`C` is provided and additional tests are added to cover the same
behaviour.

Note: Other illegal locales are not handled and will allow the
      exception to bubble up with PHP8.3+.

[1] php/php-src@a80db7b52aa134bdc8b9841

Resolves: #102095
Releases: main, 12.4
Change-Id: I26d1ab74bd9dd659363320e191874f8526845158
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/81335
Tested-by: Stefan Bürk <stefan@buerk.tech>
Tested-by: core-ci <typo3@b13.com>
Reviewed-by: Stefan Bürk <stefan@buerk.tech>
  • Loading branch information
sbuerk committed Oct 5, 2023
1 parent 13d55a0 commit ec05c5b
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 8 deletions.
10 changes: 9 additions & 1 deletion typo3/sysext/core/Classes/Localization/DateFormatter.php
Expand Up @@ -36,6 +36,10 @@ class DateFormatter
public function format(mixed $date, string|int $format, string|Locale $locale): string
{
$locale = (string)$locale;
// Use fallback locale if 'C' is provided.
if ($locale === 'C') {
$locale = 'en-US';
}
if (is_int($format) || MathUtility::canBeInterpretedAsInteger($format)) {
$dateFormatter = new \IntlDateFormatter($locale, (int)$format, (int)$format);
} else {
Expand Down Expand Up @@ -82,10 +86,14 @@ public function strftime(string $format, int|string|\DateTimeInterface|null $tim

if (empty($locale)) {
// get current locale
$locale = setlocale(LC_TIME, '0');
$locale = (string)setlocale(LC_TIME, '0');
} else {
$locale = (string)$locale;
}
// Use fallback locale if 'C' is provided.
if ($locale === 'C') {
$locale = 'en-US';
}
// remove trailing part not supported by ext-intl locale
$locale = preg_replace('/[^\w-].*$/', '', $locale);

Expand Down
49 changes: 42 additions & 7 deletions typo3/sysext/core/Tests/Unit/Localization/DateFormatterTest.php
Expand Up @@ -30,32 +30,67 @@ public static function formatDateProvider(): \Generator
"yyyy.MM.dd G 'at' HH:mm:ss zzz",
];
yield 'full - no locale' => [
'Thursday, February 2, 2023 at 13:05:00 Coordinated Universal Time',
'Thursday, February 2, 2023 at 1:05:00 PM Coordinated Universal Time',
'FULL',
];
yield 'full - locale C' => [
'Thursday, February 2, 2023 at 1:05:00 PM Coordinated Universal Time',
'FULL',
new Locale('C'),
];
yield 'long - no locale' => [
'February 2, 2023 at 13:05:00 UTC',
'February 2, 2023 at 1:05:00 PM UTC',
'LONG',
];
yield 'long - locale C' => [
'February 2, 2023 at 1:05:00 PM UTC',
'LONG',
new Locale('C'),
];
yield 'medium - no locale' => [
'Feb 2, 2023, 13:05:00',
'Feb 2, 2023, 1:05:00 PM',
'MEDIUM',
];
yield 'medium - locale C' => [
'Feb 2, 2023, 1:05:00 PM',
'MEDIUM',
new Locale('C'),
];
yield 'medium with int - no locale' => [
'Feb 2, 2023, 13:05:00',
'Feb 2, 2023, 1:05:00 PM',
\IntlDateFormatter::MEDIUM,
];
yield 'medium with int - locale C' => [
'Feb 2, 2023, 1:05:00 PM',
\IntlDateFormatter::MEDIUM,
new Locale('C'),
];
yield 'medium with int as string - no locale' => [
'Feb 2, 2023, 13:05:00',
'Feb 2, 2023, 1:05:00 PM',
(string)\IntlDateFormatter::MEDIUM,
];
yield 'medium with int as string - locale C' => [
'Feb 2, 2023, 1:05:00 PM',
(string)\IntlDateFormatter::MEDIUM,
new Locale('C'),
];
yield 'short - no locale' => [
'2/2/23, 13:05',
'2/2/23, 1:05 PM',
'SHORT',
];
yield 'short - locale C' => [
'2/2/23, 1:05 PM',
'SHORT',
new Locale('C'),
];
yield 'short in lowercase - no locale' => [
'2/2/23, 13:05',
'2/2/23, 1:05 PM',
'short',
];
yield 'short in lowercase - locale C' => [
'2/2/23, 1:05 PM',
'short',
new Locale('C'),
];
yield 'regular formatting - en-US locale' => [
'2023.02.02 AD at 13:05:00 UTC',
Expand Down

0 comments on commit ec05c5b

Please sign in to comment.