format(\DATE_RFC3339); } public static function parseDateTime(string $datetime): \DateTimeInterface { $datetime = trim($datetime); /** @var \DateTimeInterface|null */ $output = null; switch (true) { case (bool) preg_match(self::FRENCH_DATE_REGEX, $datetime): $output = self::parseFrench($datetime); break; case (bool) preg_match(self::RFC3339_REGEX, $datetime): $output = self::parseRfc3339($datetime); break; case (bool) preg_match(self::ISO8601_REGEX, $datetime): $output = self::parseIso8601($datetime); break; default: try { $output = new \DateTimeImmutable($datetime); } catch (\Exception $e) { throw new \InvalidArgumentException('Unrecognized date/time format: ' . $datetime); } } return $output; } protected static function parseFrench(string $datetime): \DateTimeInterface { $dt = \DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $datetime . ' 00:00:00'); return $dt ?: self::parseFallback($datetime); } protected static function parseRfc3339(string $datetime): \DateTimeInterface { $dt = \DateTimeImmutable::createFromFormat(\DateTime::RFC3339, $datetime); if ($dt !== false) { return $dt; } $dt = \DateTimeImmutable::createFromFormat('Y-m-d\TH:i:s.uP', $datetime); return $dt ?: self::parseFallback($datetime); } protected static function parseIso8601(string $datetime): \DateTimeInterface { $dt = \DateTimeImmutable::createFromFormat(\DateTimeInterface::ATOM, $datetime); return $dt ?: self::parseFallback($datetime); } protected static function parseFallback(string $datetime): \DateTimeInterface { try { return new \DateTimeImmutable($datetime); } catch (\Throwable $e) { throw new \InvalidArgumentException("Unrecognized date/time format: {$datetime}"); } } }