diff --git a/composer.json b/composer.json index 1cd0196..43be39c 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,9 @@ "assoconnect/php-quality-config": "^1.1" }, "require": { - "php": "^7.4|^8.0" + "php": "^7.4|^8.0", + "ext-intl": "*", + "thecodingmachine/safe": "^1.3|^2.0" }, "config": { "allow-plugins": { diff --git a/src/AbsoluteDate.php b/src/AbsoluteDate.php index 8aa6ed5..93f1f4a 100644 --- a/src/AbsoluteDate.php +++ b/src/AbsoluteDate.php @@ -14,7 +14,7 @@ class AbsoluteDate /** * AbsoluteDate constructor from a date as string - * Use createInTimezone method if you have a DateTime object or your format includes the hour part + * Use createInTimezone method if you have a DateTime instance or your format includes the hour part * * @param string $date Date as string * @param string $format Format to parse the provided date @@ -97,7 +97,7 @@ private function getDateTimeFromFormatAndTimezone(string $format, \DateTimeZone } /** - * Checks whether the value represented by this object equals to the other. + * Checks whether the date represented by this instance equals to the other. */ public function equalsTo(self $other): bool { @@ -138,7 +138,7 @@ public function isBeforeOrEqualTo(self $other): bool } /** - * Returns whether this instant is after another. + * Returns whether this date is after another. */ public function isAfter(self $other): bool { @@ -146,7 +146,7 @@ public function isAfter(self $other): bool } /** - * Returns whether this instant is after or equal to another. + * Returns whether this date is after or equal to another. */ public function isAfterOrEqualTo(self $other): bool { @@ -172,7 +172,7 @@ public function __toString(): string } /** - * Returns an AbsoluteDate object + * Returns an AbsoluteDate instance * * @param \DateTimeZone $timezone Timezone to use to get the right date * @param \DateTimeInterface|null $datetime Point in time to find the date from @@ -187,7 +187,7 @@ public static function createInTimezone(\DateTimeZone $timezone, \DateTimeInterf } /** - * Returns an AbsoluteDate object from a relative format in a given timezone + * Returns an AbsoluteDate instance from a relative format in a given timezone * * @param string $relative Relative format to use * @param ?\DateTimeZone $timezone Timezone to use to get the right date diff --git a/src/Exception/UnknownPatternException.php b/src/Exception/UnknownPatternException.php new file mode 100644 index 0000000..8c879d4 --- /dev/null +++ b/src/Exception/UnknownPatternException.php @@ -0,0 +1,9 @@ +getPatternFromLocale($locale)), // IntlDateFormatter pattern + explode('/', $date) + ); + $orderedDateParts = ['', '', '']; + $patternParts = ['', '', '']; // DateTimeInterface pattern + foreach ($parts as $pattern => $value) { + switch ($pattern) { + case 'd': // Day without leading 0 + case 'dd': // Day with leading 0 + $orderedDateParts[2] = str_pad($value, 2, '0', STR_PAD_LEFT); + $patternParts[2] = 'd'; + break; + case 'M': // Month without leading 0 + case 'MM': // Month with leading 0 + $orderedDateParts[1] = str_pad($value, 2, '0', STR_PAD_LEFT); + $patternParts[1] = 'm'; + break; + case 'y': // Year on 4 digits + case 'yy': // Year on 2 digits + case 'yyyy': // Year on 4 digits + $orderedDateParts[0] = $value; + $patternParts[0] = (2 === strlen($value)) ? 'y' : 'Y'; + break; + default: + throw new UnknownPatternException($pattern); + } + } + return new AbsoluteDate( + implode('-', $orderedDateParts), + implode('-', $patternParts) + ); + } + + public function getPatternFromLocale(string $locale): string + { + return (new IntlDateFormatter( + $locale, + IntlDateFormatter::SHORT, + IntlDateFormatter::NONE, + ))->getPattern(); + } +} diff --git a/tests/LocalizedStringParserTest.php b/tests/LocalizedStringParserTest.php new file mode 100644 index 0000000..4fac2a6 --- /dev/null +++ b/tests/LocalizedStringParserTest.php @@ -0,0 +1,30 @@ +create($formattedDate, $locale)->format()); + } + + /** @return array{string, string, string}[] */ + public function provideStringsAndLocales(): iterable + { + yield ['09/01/2023', 'en_US', '2023-09-01']; + yield ['9/1/2023', 'en_US', '2023-09-01']; + yield ['9/1/23', 'en_US', '2023-09-01']; + + yield ['09/01/2023', 'fr_FR', '2023-01-09']; + yield ['9/1/2023', 'fr_FR', '2023-01-09']; + yield ['9/1/23', 'fr_FR', '2023-01-09']; + } +}