diff --git a/src/DateInStringFinder.php b/src/DateInStringFinder.php index dda1733..e561ca7 100644 --- a/src/DateInStringFinder.php +++ b/src/DateInStringFinder.php @@ -85,11 +85,18 @@ final class DateInStringFinder */ public static function find(string $string): array { + $day = null; $month = null; $year = null; - [$day, $month, $year] = self::getSimpleDate($string) ?? self::getComplexDate($string); + [$day, $month, $year] = self::getIsoDate($string) ?? self::getSimpleDate($string) ?? self::getComplexDate($string); + + // Only if we did not succeed in getting a year do we try to find + // two-digit years. And maybe only if no day or month either? + if ($year === null) { + [$day, $month, $year] = self::getSimpleDate($string, TRUE) ?? self::getComplexDate($string, TRUE); + } // Match month name: if ($month === null) { @@ -108,6 +115,16 @@ public static function find(string $string): array } } + // Match YYYY-MM to Year and Month if not already set: + if ($year === null && $month === null) { + preg_match('/\d{4}[\-\.\/]\d{2}/', $string, $matches_year_month); + if ($matches_year_month && $matches_year_month[0]) { + $year_month = $matches_year_month[0]; + $year_month = str_replace(['.', '/'], '-', $year_month); + [$year, $month] = explode('-', $year_month); + } + } + // Match Year if not already set: if ($year === null) { preg_match('/\d{4}/', $string, $matches_year); @@ -115,6 +132,7 @@ public static function find(string $string): array $year = $matches_year[0]; } } + if ($year === null) { preg_match('/\'(\d{2})/', $string, $matches_year); if ($matches_year && $matches_year[1]) { @@ -134,11 +152,16 @@ public static function find(string $string): array /** * @return int[]|null */ - private static function getSimpleDate(string $string): ?array + private static function getSimpleDate(string $string, bool $two_digit_year = FALSE): ?array { + $year_pattern = '(\d{4})'; + if ($two_digit_year) { + $year_pattern = '(\d{2})'; + } + // Match dates: 01/01/2012 or 30-12-11 or 1 2 1985 preg_match( - '/(\d?\d)([.\-\/ ])+([0-1]?\d)\2+(\d{2,4})/', + '/(\d?\d)([.\-\/ ])+([0-1]?\d)\2+' . $year_pattern . '/', $string, $matches ); @@ -153,11 +176,15 @@ private static function getSimpleDate(string $string): ?array return null; } - private static function getComplexDate(string $string): ?array + private static function getComplexDate(string $string, bool $two_digit_year = FALSE): ?array { + $year_pattern = '(\d{4})'; + if ($two_digit_year) { + $year_pattern = '\'(\d{2})'; + } // Match dates: Sunday 1st March 2015; Sunday, 1 March 2015; Sun 1 Mar 2015; Sun-1-March-2015 preg_match( - '/(?:(?:'.implode('|', self::DAYS).'|'.implode('|', self::SHORT_DAYS).')[ ,\-_\/]*)?(\d?\d)[ ,\-_\/]*(?:'.implode('|', self::ORDINALS).')?[ ,\-_\/(?:of)]*('.implode('|', self::MONTHS).'|'.implode('|', self::SHORT_MONTHS).')\b(?:[ ,\-_\/]+(?:(\d{4})|\'(\d{2})))?/i', + '/(?:(?:'.implode('|', self::DAYS).'|'.implode('|', self::SHORT_DAYS).')[ ,\-_\/]*)?(\d?\d)[ ,\-_\/]*(?:'.implode('|', self::ORDINALS).')?[ ,\-_\/(?:of)]*('.implode('|', self::MONTHS).'|'.implode('|', self::SHORT_MONTHS).')\b(?:[ ,\-_\/]+(?:' .$year_pattern . '))?/i', $string, $matches ); @@ -171,7 +198,7 @@ private static function getComplexDate(string $string): ?array // Match dates: March 1st 2015; March 1 2015; March-1st-2015 preg_match( - '/('.implode('|', self::MONTHS).'|'.implode('|', self::SHORT_MONTHS).')\b[ ,\-_\/]*(\d?\d)[ ,\-_\/]*(?:'.implode('|', self::ORDINALS).')?[ ,\-_\/]+(?:(\d{4})|\'(\d{2}))/i', + '/('.implode('|', self::MONTHS).'|'.implode('|', self::SHORT_MONTHS).')\b[ ,\-_\/]*(\d?\d)[ ,\-_\/]*(?:'.implode('|', self::ORDINALS).')?[ ,\-_\/]+(?:' . $year_pattern . ')/i', $string, $matches ); @@ -192,6 +219,26 @@ private static function getComplexDate(string $string): ?array ]; } + /** + * @return int[]|null + */ + private static function getIsoDate(string $string): ?array + { + + // Match dates: 2025-06-30 or 2025/06/30 or 2025 06 30 as well as + // more unusual combinations likely in directories like 2025-06/30/19 + preg_match('/(\d{4})[.\-\/ ](\d{2})[.\-\/ ](\d{2})/', $string, $matches); + if (($matches[1] ?? null) !== null && ($matches[2] ?? null) !== null && ($matches[3] ?? null) !== null) { + return [ + $matches[3] ?? null, + $matches[2] ?? null, + $matches[1] ?? null, + ]; + } + + return null; + } + private static function getMonthNumber(string $initialMonth): ?int { $month = array_search(strtolower($initialMonth), self::SHORT_MONTHS, true); diff --git a/tests/DateInStringFinderTest.php b/tests/DateInStringFinderTest.php index 8e1e426..c44376b 100644 --- a/tests/DateInStringFinderTest.php +++ b/tests/DateInStringFinderTest.php @@ -80,6 +80,38 @@ public function dataStringDataProvider(): array 'year' => 11, ], ], + [ + 'uploads/2025-06/example.pdf', + [ + 'day' => null, + 'month' => 06, + 'year' => 2025, + ], + ], + [ + 'uploads/2025-06/17/example.pdf', + [ + 'day' => 17, + 'month' => 06, + 'year' => 2025, + ], + ], + [ + 'uploads/2025-06/example.pdf', + [ + 'day' => null, + 'month' => 06, + 'year' => 2025, + ], + ], + [ + '2025-06-17', + [ + 'day' => 17, + 'month' => 06, + 'year' => 2025, + ], + ], [ '1 2 1985', [