57 lines
1.8 KiB
PHP
57 lines
1.8 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
class DateNormalizer
|
|
{
|
|
/**
|
|
* Normalize a raw date string to Y-m-d (ISO) or return null if unparseable.
|
|
* Accepted examples: 30.10.2025, 30/10/2025, 30-10-2025, 1/2/25, 2025-10-30
|
|
*/
|
|
public static function toDate(?string $raw): ?string
|
|
{
|
|
if ($raw === null) {
|
|
return null;
|
|
}
|
|
$raw = trim($raw);
|
|
if ($raw === '') {
|
|
return null;
|
|
}
|
|
|
|
// Common European and ISO formats first (day-first, then ISO)
|
|
$candidates = [
|
|
'd.m.Y', 'd.m.y',
|
|
'd/m/Y', 'd/m/y',
|
|
'd-m-Y', 'd-m-y',
|
|
'Y-m-d', 'Y/m/d', 'Y.m.d',
|
|
];
|
|
|
|
foreach ($candidates as $fmt) {
|
|
$dt = \DateTime::createFromFormat($fmt, $raw);
|
|
if ($dt instanceof \DateTime) {
|
|
$errors = \DateTime::getLastErrors();
|
|
if ((int) ($errors['warning_count'] ?? 0) === 0 && (int) ($errors['error_count'] ?? 0) === 0) {
|
|
// Adjust two-digit years to reasonable century (00-69 => 2000-2069, 70-99 => 1970-1999)
|
|
$year = (int) $dt->format('Y');
|
|
if ($year < 100) {
|
|
$year += ($year <= 69) ? 2000 : 1900;
|
|
// Rebuild date with corrected year
|
|
$month = (int) $dt->format('m');
|
|
$day = (int) $dt->format('d');
|
|
return sprintf('%04d-%02d-%02d', $year, $month, $day);
|
|
}
|
|
return $dt->format('Y-m-d');
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fallback: strtotime (permissive). If fails, return null.
|
|
$ts = @strtotime($raw);
|
|
if ($ts === false) {
|
|
return null;
|
|
}
|
|
|
|
return date('Y-m-d', $ts);
|
|
}
|
|
}
|