Skip to content

Commit

Permalink
Handle when "DateTimeImmutable" cannot parse the given date
Browse files Browse the repository at this point in the history
In some cases, "DateTimeImmutable" will throw an exception because it
cannot parse the date. In those cases, we shouldn't throw an exception,
but instead return a specific result that tells what happened.
  • Loading branch information
henriquemoody committed Dec 13, 2024
1 parent 82cb05b commit 1093ab3
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 2 deletions.
16 changes: 14 additions & 2 deletions library/Rules/DateTimeDiff.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Respect\Validation\Result;
use Respect\Validation\Rule;
use Respect\Validation\Rules\Core\Standard;
use Throwable;

use function array_map;
use function in_array;
Expand All @@ -32,6 +33,11 @@
'The number of {{type|trans}} between {{now|raw}} and',
self::TEMPLATE_CUSTOMIZED
)]
#[Template(
'For comparison with {{now|raw}}, {{name}} must be a valid datetime',
'For comparison with {{now|raw}}, {{name}} must not be a valid datetime',
self::TEMPLATE_NOT_A_DATE
)]
#[Template(
'For comparison with {{now|raw}}, {{name}} must be a valid datetime in the format {{sample|raw}}',
'For comparison with {{now|raw}}, {{name}} must not be a valid datetime in the format {{sample|raw}}',
Expand All @@ -42,6 +48,7 @@ final class DateTimeDiff extends Standard
use CanValidateDateTime;

public const TEMPLATE_CUSTOMIZED = '__customized__';
public const TEMPLATE_NOT_A_DATE = '__not_a_date__';
public const TEMPLATE_WRONG_FORMAT = '__wrong_format__';

/** @param "years"|"months"|"days"|"hours"|"minutes"|"seconds"|"microseconds" $type */
Expand All @@ -66,9 +73,10 @@ public function evaluate(mixed $input): Result
$now = $this->now ?? new DateTimeImmutable();
$compareTo = $this->createDateTimeObject($input);
if ($compareTo === null) {
$template = $this->format === null ? self::TEMPLATE_NOT_A_DATE : self::TEMPLATE_WRONG_FORMAT;
$parameters = ['sample' => $now->format($this->format ?? 'c'), 'now' => $this->nowParameter($now)];

return Result::failed($input, $this, $parameters, self::TEMPLATE_WRONG_FORMAT)
return Result::failed($input, $this, $parameters, $template)
->withId('dateTimeDiff' . ucfirst($this->rule->evaluate($input)->id));
}

Expand Down Expand Up @@ -132,7 +140,11 @@ private function createDateTimeObject(mixed $input): ?DateTimeInterface
}

if ($this->format === null) {
return new DateTimeImmutable((string) $input);
try {
return new DateTimeImmutable((string) $input);
} catch (Throwable) {
return null;
}
}

$format = $this->getExceptionalFormats()[$this->format] ?? $this->format;
Expand Down
9 changes: 9 additions & 0 deletions tests/integration/rules/dateTimeDiff.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ run([
'With $type = "minutes"' => [v::dateTimeDiff('minutes', v::equals(6)), '5 minutes ago'],
'With $type = "microseconds"' => [v::dateTimeDiff('microseconds', v::equals(7)), '6 microseconds ago'],
'With custom $format' => [v::dateTimeDiff('years', v::lessThan(8), 'd/m/Y'), '09/12/1988'],
'With input in non-parseable date' => [v::dateTimeDiff('years', v::equals(2)), 'not a date'],
'With input in incorrect $format' => [v::dateTimeDiff('years', v::equals(2), 'Y-m-d'), '1 year ago'],
'With custom $now' => [v::dateTimeDiff('years', v::lessThan(9), null, new DateTimeImmutable()), '09/12/1988'],
'With custom template' => [v::dateTimeDiff('years', v::equals(2)->setTemplate('Custom template')), '1 year ago'],
Expand Down Expand Up @@ -99,6 +100,14 @@ The number of years between %d/%d/%d and %d/%d/%d must be less than 8
'dateTimeDiffLessThan' => 'The number of years between %d/%d/%d and %d/%d/%d must be less than 8',
]

With input in non-parseable date
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
For comparison with now, "not a date" must be a valid datetime
- For comparison with now, "not a date" must be a valid datetime
[
'dateTimeDiffEquals' => 'For comparison with now, "not a date" must be a valid datetime',
]

With input in incorrect $format
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
For comparison with %d-%d-%d, "1 year ago" must be a valid datetime in the format %d-%d-%d
Expand Down

0 comments on commit 1093ab3

Please sign in to comment.