From d6b97e363894c86fc9001478fb30b4852f713101 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Mon, 20 Nov 2023 02:37:13 +0100 Subject: [PATCH] added filters |localDate & |localTime WIP --- composer.json | 1 + src/Latte/Essential/CoreExtension.php | 1 + src/Latte/Essential/Filters.php | 38 ++++++++++++++++++++++----- tests/filters/localDate.phpt | 38 +++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 7 deletions(-) create mode 100644 tests/filters/localDate.phpt diff --git a/composer.json b/composer.json index 44d1bb1cf..f42eab550 100644 --- a/composer.json +++ b/composer.json @@ -30,6 +30,7 @@ "ext-iconv": "to use filters |reverse, |substring", "ext-mbstring": "to use filters like lower, upper, capitalize, ...", "ext-fileinfo": "to use filter |datastream", + "ext-intl": "to use filters |localDate, |localTime", "nette/utils": "to use filter |webalize", "nette/php-generator": "to use tag {templatePrint}" }, diff --git a/src/Latte/Essential/CoreExtension.php b/src/Latte/Essential/CoreExtension.php index 63346bbe2..7982a1f21 100644 --- a/src/Latte/Essential/CoreExtension.php +++ b/src/Latte/Essential/CoreExtension.php @@ -141,6 +141,7 @@ public function getFilters(): array 'join' => [Filters::class, 'implode'], 'last' => [Filters::class, 'last'], 'length' => [Filters::class, 'length'], + 'localDate' => [Filters::class, 'localDate'], 'lower' => extension_loaded('mbstring') ? [Filters::class, 'lower'] : function () { throw new RuntimeException('Filter |lower requires mbstring extension.'); }, diff --git a/src/Latte/Essential/Filters.php b/src/Latte/Essential/Filters.php index 9c07ecca0..603681e0c 100644 --- a/src/Latte/Essential/Filters.php +++ b/src/Latte/Essential/Filters.php @@ -172,17 +172,12 @@ public static function date(string|int|\DateTimeInterface|\DateInterval|null $ti return null; } - if (!isset($format)) { - $format = Latte\Runtime\Filters::$dateFormat; - } - + $format ??= Latte\Runtime\Filters::$dateFormat; if ($time instanceof \DateInterval) { return $time->format($format); } elseif (is_numeric($time)) { - $time = new \DateTime('@' . $time); - $time->setTimeZone(new \DateTimeZone(date_default_timezone_get())); - + $time = (new \DateTime)->setTimestamp((int) $time); } elseif (!$time instanceof \DateTimeInterface) { $time = new \DateTime($time); } @@ -199,6 +194,35 @@ public static function date(string|int|\DateTimeInterface|\DateInterval|null $ti } + /** + * Local date/time formatting. + * https://unicode-org.github.io/icu/userguide/format_parse/datetime/#datetime-format-syntax + */ + public static function localDate(string|int|\DateTimeInterface|null $time, string $format = 'medium'): ?string + { + if (!class_exists(\IntlDateFormatter::class)) { + throw new Latte\RuntimeException("Filters |localDate and |localTime requires 'intl' extension."); + } elseif ($time == null) { // intentionally == + return null; + } elseif (is_numeric($time)) { + $time = (new \DateTime)->setTimestamp((int) $time); + } elseif (is_string($time)) { + $time = new \DateTime($time); + } + + $format = match ($format) { + 'time' => [\IntlDateFormatter::NONE, \IntlDateFormatter::SHORT], + 'timeSec' => [\IntlDateFormatter::NONE, \IntlDateFormatter::MEDIUM], + 'short' => [\IntlDateFormatter::SHORT, \IntlDateFormatter::NONE], + 'medium' => [\IntlDateFormatter::MEDIUM, \IntlDateFormatter::NONE], + 'long' => [\IntlDateFormatter::LONG, \IntlDateFormatter::NONE], + 'full' => [\IntlDateFormatter::FULL, \IntlDateFormatter::NONE], + default => $format, + }; + return preg_replace('~(\d\.) ~', "\$1\u{a0}", \IntlDateFormatter::formatObject($time, $format)); + } + + /** * Converts to human readable file size. */ diff --git a/tests/filters/localDate.phpt b/tests/filters/localDate.phpt new file mode 100644 index 000000000..b75959153 --- /dev/null +++ b/tests/filters/localDate.phpt @@ -0,0 +1,38 @@ +