diff --git a/docs/rules/DateTime.md b/docs/rules/DateTime.md index 83813e9c..84c6e7ff 100644 --- a/docs/rules/DateTime.md +++ b/docs/rules/DateTime.md @@ -1,16 +1,20 @@ + # DateTime - `DateTime()` - `DateTime(string $format)` -Validates whether an input is a date/time or not. The `$format` argument should -be in accordance to PHP's [date()](http://php.net/date) function. +Validates whether an input is a date/time or not. + +The `$format` argument should be in accordance to [DateTime::format()][]. See more in the [Formats](#formats) section. + +When a `$format` is not given its default value is `Y-m-d H:i:s`. ```php v::dateTime()->validate('2009-01-01'); // true ``` -Also accepts strtotime values: +Also accepts [strtotime()](http://php.net/strtotime) values: ```php v::dateTime()->validate('now'); // true @@ -31,7 +35,26 @@ v::dateTime('Y-m-d')->validate('01-01-2009'); // false Format has no effect when validating DateTime instances. -Message template for this validator includes `{{format}}`. +Message template for this validator includes `{{sample}}`. + +## Formats + +Note that this rule validates whether the input **matches a given [DateTime::format()][] format** and **NOT if the input +can be parsed with a given [DateTimeImmutable::createFromFormat()][] format**. That makes the validation stricter but +offers some limitations. + +The way [DateTimeImmutable::createFromFormat()][] parses an input allows for many different conversions. Overall +[DateTimeImmutable::createFromFormat()][] tend to be more lenient than [DateTime::format()][]. This might be what +you desire, and you may want to use [Callback](Callback.md) to create a custom validation. + +```php +$input = '2014-04-12T23:20:50.052Z'; + +v::callback(fn($input) => is_string($input) && DateTime::createFromFormat(DateTime::RFC3339_EXTENDED, $input)) + ->validate($input); // true + +v::dateTime(DateTime::RFC3339_EXTENDED)->validate($input); // false +``` ## Categorization @@ -39,10 +62,11 @@ Message template for this validator includes `{{format}}`. ## Changelog -Version | Description ---------|------------- - 2.2.4 | `v::dateTime('z')` is no longer supported. - 2.0.0 | Created +| Version | Description | +|---------|--------------------------------------------| +| 2.3.0 | Validation became a lot stricter | +| 2.2.4 | `v::dateTime('z')` is no longer supported. | +| 2.0.0 | Created | *** See also: @@ -53,3 +77,6 @@ See also: - [LeapYear](LeapYear.md) - [MinAge](MinAge.md) - [Time](Time.md) + +[DateTimeImmutable::createFromFormat()]: https://www.php.net/datetimeimmutable.createfromformat +[DateTime::format()]: https://www.php.net/datetime.format diff --git a/tests/library/RuleTestCase.php b/tests/library/RuleTestCase.php index bdd95139..c76ff8de 100644 --- a/tests/library/RuleTestCase.php +++ b/tests/library/RuleTestCase.php @@ -16,6 +16,8 @@ use function ltrim; use function realpath; use function Respect\Stringifier\stringify; use function sprintf; +use function strrchr; +use function substr; /** * Abstract class to create TestCases for Rules. @@ -98,7 +100,11 @@ abstract class RuleTestCase extends TestCase { self::assertTrue( $rule->validate($input), - sprintf('Validation with input %s is expected to pass', stringify($input)) + sprintf( + '%s should pass with %s', + substr((string) strrchr($rule::class, '\\'), 1), + stringify($rule->reportError($input)->getParams()) + ) ); } @@ -109,7 +115,11 @@ abstract class RuleTestCase extends TestCase { self::assertFalse( $rule->validate($input), - sprintf('Validation with input %s it not expected to pass', stringify($input)) + sprintf( + '%s should not pass with %s', + substr((string) strrchr($rule::class, '\\'), 1), + stringify($rule->reportError($input)->getParams()) + ) ); } } diff --git a/tests/unit/Rules/DateTimeTest.php b/tests/unit/Rules/DateTimeTest.php index 67eefa40..09790cee 100644 --- a/tests/unit/Rules/DateTimeTest.php +++ b/tests/unit/Rules/DateTimeTest.php @@ -11,6 +11,7 @@ namespace Respect\Validation\Rules; use DateTime as DateTimeMutable; use DateTimeImmutable; +use DateTimeInterface; use Respect\Validation\Test\RuleTestCase; use function date_default_timezone_get; @@ -102,6 +103,8 @@ final class DateTimeTest extends RuleTestCase [new DateTime('U'), 1464658596], [new DateTime('h'), 6], [new DateTime('Ym'), 202305], + [new DateTime(DateTimeInterface::RFC3339), '2018-02-23T12:00:00+00:00'], + [new DateTime(DateTimeInterface::RFC3339_EXTENDED), '2024-02-04T14:14:47.000+00:00'], ]; } @@ -123,6 +126,8 @@ final class DateTimeTest extends RuleTestCase [new DateTime('c'), new DateTimeMutable()], [new DateTime('c'), new DateTimeImmutable()], [new DateTime('Y-m-d H:i:s'), '21-3-123:12:01'], + [new DateTime(DateTimeInterface::RFC3339_EXTENDED), '2005-12-30T01:02:03Z'], + [new DateTime(DateTimeInterface::RFC3339_EXTENDED), '1937-01-01T12:00:27.87+00:20'], ]; } }