Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 53 additions & 6 deletions src/DateInStringFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -108,13 +115,24 @@ 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);
if ($matches_year && $matches_year[0]) {
$year = $matches_year[0];
}
}

if ($year === null) {
preg_match('/\'(\d{2})/', $string, $matches_year);
if ($matches_year && $matches_year[1]) {
Expand All @@ -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
);
Expand All @@ -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
);
Expand All @@ -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
);
Expand All @@ -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);
Expand Down
32 changes: 32 additions & 0 deletions tests/DateInStringFinderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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',
[
Expand Down