Skip to content

Commit

Permalink
[5.5] Fixed date comparison validators failing when a format is speci…
Browse files Browse the repository at this point in the history
…fied (#20940)

* Fixed Validator failing on 'before_or_equal:today' when the input is today's date and a format is specified

The issue was that the time part was bleeding through from the current timestamp in `DateTime::createFromFormat`.
Test case:
* Validation rule: 'birth_date' => ['required', 'date_format:Y-m-d', 'before_or_equal:today']
* '2017-08-27' was parsed as '2017-08-27 22:41:37'.
* 'today' was parsed as '2017-08-27 00:00:00'.
* Validation failed.

* Added date validator tests for time fields

This shows that the fix in 1b651e6 is not going to break applications, people can still use the time part.
This should address the comment of @taylorotwell at #20789 .

* Fixed Validator failing on 'date_equals' when a format is specified

Also added a number of test cases.
The issue was that `===` always returns false for the two separate DateTime instances returned by `getDateTimeWithOptionalFormat`.
  • Loading branch information
pantherdd authored and taylorotwell committed Sep 5, 2017
1 parent 866e465 commit 48f4f0c
Show file tree
Hide file tree
Showing 2 changed files with 174 additions and 15 deletions.
12 changes: 6 additions & 6 deletions src/Illuminate/Validation/Concerns/ValidatesAttributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ protected function checkDateTimeOrder($format, $first, $second, $operator)
*/
protected function getDateTimeWithOptionalFormat($format, $value)
{
if ($date = DateTime::createFromFormat($format, $value)) {
if ($date = DateTime::createFromFormat('!'.$format, $value)) {
return $date;
}

Expand Down Expand Up @@ -358,11 +358,11 @@ public function validateDateFormat($attribute, $value, $parameters)
return false;
}

$format = $parameters[0] == 'Y-m' ? '!Y-m' : $parameters[0];
$format = $parameters[0];

$date = DateTime::createFromFormat($format, $value);
$date = DateTime::createFromFormat('!'.$format, $value);

return $date && $date->format($parameters[0]) == $value;
return $date && $date->format($format) == $value;
}

/**
Expand All @@ -375,7 +375,7 @@ public function validateDateFormat($attribute, $value, $parameters)
*/
public function validateDateEquals($attribute, $value, $parameters)
{
$this->requireParameterCount(1, $parameters, 'equals');
$this->requireParameterCount(1, $parameters, 'date_equals');

return $this->compareDates($attribute, $value, $parameters, '=');
}
Expand Down Expand Up @@ -1432,7 +1432,7 @@ protected function compare($first, $second, $operator)
case '>=':
return $first >= $second;
case '=':
return $first === $second;
return $first == $second;
default:
throw new InvalidArgumentException;
}
Expand Down
177 changes: 168 additions & 9 deletions tests/Validation/ValidationValidatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2312,9 +2312,6 @@ public function testValidateDateAndFormat()
$v = new Validator($trans, ['x' => '2000-01-01'], ['x' => 'date_format:Y-m-d']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => '2000-01-01 17:43:59'], ['x' => 'date_format:Y-m-d H:i:s']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => '01/01/2001'], ['x' => 'date_format:Y-m-d']);
$this->assertTrue($v->fails());

Expand Down Expand Up @@ -2342,6 +2339,21 @@ public function testValidateDateAndFormat()

$v = new Validator($trans, ['x' => '2000-01-01T00:00:00+00:30'], ['x' => 'date_format:Y-m-d\TH:i:sP']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => '2000-01-01 17:43:59'], ['x' => 'date_format:Y-m-d H:i:s']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => '2000-01-01 17:43:59'], ['x' => 'date_format:H:i:s']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '17:43:59'], ['x' => 'date_format:H:i:s']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => '17:43:59'], ['x' => 'date_format:H:i']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '17:43'], ['x' => 'date_format:H:i']);
$this->assertTrue($v->passes());
}

public function testDateEquals()
Expand All @@ -2359,6 +2371,51 @@ public function testDateEquals()

$v = new Validator($trans, ['start' => new DateTime('2000-01-01'), 'ends' => new DateTime('2000-01-01')], ['ends' => 'date_equals:start']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => date('Y-m-d')], ['x' => 'date_equals:today']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => date('Y-m-d')], ['x' => 'date_equals:yesterday']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => date('Y-m-d')], ['x' => 'date_equals:tomorrow']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => date('d/m/Y')], ['x' => 'date_format:d/m/Y|date_equals:today']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => date('d/m/Y')], ['x' => 'date_format:d/m/Y|date_equals:yesterday']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => date('d/m/Y')], ['x' => 'date_format:d/m/Y|date_equals:tomorrow']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '2012-01-01 17:44:00'], ['x' => 'date_format:Y-m-d H:i:s|date_equals:2012-01-01 17:44:00']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => '2012-01-01 17:44:00'], ['x' => 'date_format:Y-m-d H:i:s|date_equals:2012-01-01 17:43:59']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '2012-01-01 17:44:00'], ['x' => 'date_format:Y-m-d H:i:s|date_equals:2012-01-01 17:44:01']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '17:44:00'], ['x' => 'date_format:H:i:s|date_equals:17:44:00']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => '17:44:00'], ['x' => 'date_format:H:i:s|date_equals:17:43:59']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '17:44:00'], ['x' => 'date_format:H:i:s|date_equals:17:44:01']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '17:44'], ['x' => 'date_format:H:i|date_equals:17:44']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => '17:44'], ['x' => 'date_format:H:i|date_equals:17:43']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '17:44'], ['x' => 'date_format:H:i|date_equals:17:45']);
$this->assertTrue($v->fails());
}

public function testBeforeAndAfter()
Expand Down Expand Up @@ -2415,6 +2472,30 @@ public function testBeforeAndAfter()

$v = new Validator($trans, ['start' => 'today', 'ends' => 'tomorrow'], ['start' => 'Before:ends', 'ends' => 'After:start']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => '2012-01-01 17:43:59'], ['x' => 'Before:2012-01-01 17:44|After:2012-01-01 17:43:58']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => '2012-01-01 17:44:01'], ['x' => 'Before:2012-01-01 17:44:02|After:2012-01-01 17:44']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => '2012-01-01 17:44'], ['x' => 'Before:2012-01-01 17:44:00']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '2012-01-01 17:44'], ['x' => 'After:2012-01-01 17:44:00']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '17:43:59'], ['x' => 'Before:17:44|After:17:43:58']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => '17:44:01'], ['x' => 'Before:17:44:02|After:17:44']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => '17:44'], ['x' => 'Before:17:44:00']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '17:44'], ['x' => 'After:17:44:00']);
$this->assertTrue($v->fails());
}

public function testBeforeAndAfterWithFormat()
Expand Down Expand Up @@ -2469,13 +2550,46 @@ public function testBeforeAndAfterWithFormat()
$v = new Validator($trans, ['x' => date('d/m/Y')], ['x' => 'date_format:d/m/Y|after:yesterday|before:tomorrow']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => date('d/m/Y')], ['x' => 'date_format:d/m/Y|after:tomorrow|before:yesterday']);
$v = new Validator($trans, ['x' => date('d/m/Y')], ['x' => 'date_format:d/m/Y|after:today']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => date('d/m/Y')], ['x' => 'date_format:d/m/Y|before:today']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => date('Y-m-d')], ['x' => 'after:yesterday|before:tomorrow']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => date('Y-m-d')], ['x' => 'after:tomorrow|before:yesterday']);
$v = new Validator($trans, ['x' => date('Y-m-d')], ['x' => 'after:today']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => date('Y-m-d')], ['x' => 'before:today']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '2012-01-01 17:44:00'], ['x' => 'date_format:Y-m-d H:i:s|before:2012-01-01 17:44:01|after:2012-01-01 17:43:59']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => '2012-01-01 17:44:00'], ['x' => 'date_format:Y-m-d H:i:s|before:2012-01-01 17:44:00']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '2012-01-01 17:44:00'], ['x' => 'date_format:Y-m-d H:i:s|after:2012-01-01 17:44:00']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '17:44:00'], ['x' => 'date_format:H:i:s|before:17:44:01|after:17:43:59']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => '17:44:00'], ['x' => 'date_format:H:i:s|before:17:44:00']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '17:44:00'], ['x' => 'date_format:H:i:s|after:17:44:00']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '17:44'], ['x' => 'date_format:H:i|before:17:45|after:17:43']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => '17:44'], ['x' => 'date_format:H:i|before:17:44']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '17:44'], ['x' => 'date_format:H:i|after:17:44']);
$this->assertTrue($v->fails());
}

Expand All @@ -2492,10 +2606,19 @@ public function testWeakBeforeAndAfter()
$v = new Validator($trans, ['x' => '2012-01-15'], ['x' => 'before_or_equal:2012-01-14']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '31/12/2012'], ['x' => 'date_format:d/m/Y|before_or_equal:31/12/2012']);
$v = new Validator($trans, ['x' => '15/01/2012'], ['x' => 'date_format:d/m/Y|before_or_equal:15/01/2012']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => '15/01/2012'], ['x' => 'date_format:d/m/Y|before_or_equal:14/01/2012']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => date('d/m/Y')], ['x' => 'date_format:d/m/Y|before_or_equal:today']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => date('d/m/Y')], ['x' => 'date_format:d/m/Y|before_or_equal:tomorrow']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => '31/12/2012'], ['x' => 'date_format:d/m/Y|before_or_equal:29/12/2012']);
$v = new Validator($trans, ['x' => date('d/m/Y')], ['x' => 'date_format:d/m/Y|before_or_equal:yesterday']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '2012-01-15'], ['x' => 'after_or_equal:2012-01-15']);
Expand All @@ -2507,10 +2630,46 @@ public function testWeakBeforeAndAfter()
$v = new Validator($trans, ['x' => '2012-01-15'], ['x' => 'after_or_equal:2012-01-16']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '31/12/2012'], ['x' => 'date_format:d/m/Y|after_or_equal:31/12/2012']);
$v = new Validator($trans, ['x' => '15/01/2012'], ['x' => 'date_format:d/m/Y|after_or_equal:15/01/2012']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => '15/01/2012'], ['x' => 'date_format:d/m/Y|after_or_equal:16/01/2012']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => date('d/m/Y')], ['x' => 'date_format:d/m/Y|after_or_equal:today']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => date('d/m/Y')], ['x' => 'date_format:d/m/Y|after_or_equal:yesterday']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => date('d/m/Y')], ['x' => 'date_format:d/m/Y|after_or_equal:tomorrow']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '2012-01-01 17:44:00'], ['x' => 'date_format:Y-m-d H:i:s|before_or_equal:2012-01-01 17:44:00|after_or_equal:2012-01-01 17:44:00']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => '31/12/2012'], ['x' => 'date_format:d/m/Y|after_or_equal:02/01/2013']);
$v = new Validator($trans, ['x' => '2012-01-01 17:44:00'], ['x' => 'date_format:Y-m-d H:i:s|before_or_equal:2012-01-01 17:43:59']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '2012-01-01 17:44:00'], ['x' => 'date_format:Y-m-d H:i:s|after_or_equal:2012-01-01 17:44:01']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '17:44:00'], ['x' => 'date_format:H:i:s|before_or_equal:17:44:00|after_or_equal:17:44:00']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => '17:44:00'], ['x' => 'date_format:H:i:s|before_or_equal:17:43:59']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '17:44:00'], ['x' => 'date_format:H:i:s|after_or_equal:17:44:01']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '17:44'], ['x' => 'date_format:H:i|before_or_equal:17:44|after_or_equal:17:44']);
$this->assertTrue($v->passes());

$v = new Validator($trans, ['x' => '17:44'], ['x' => 'date_format:H:i|before_or_equal:17:43']);
$this->assertTrue($v->fails());

$v = new Validator($trans, ['x' => '17:44'], ['x' => 'date_format:H:i|after_or_equal:17:45']);
$this->assertTrue($v->fails());
}

Expand Down

0 comments on commit 48f4f0c

Please sign in to comment.