1

I want to validate a string to see if it is a valid date in the format YYYY-MM-DD. I'm not very good with regex, but I've managed to get it to validate strings with four 0-9 characters in the beginning followed by the hyphen, followed by two 0-9 chars, another hyphen, and two more 0-9 chars in the end. How could I make this regex match dates with only 1-12 in the month and 1-31 in the day?

Here's what I have so far:

([0-9]{4})-([0-9]{2})-([0-9]{2})
ShoeLace1291
  • 4,551
  • 12
  • 45
  • 81

2 Answers2

1

A simple way:

$pattern = '~\A(\d{4})-(\d{2})-(\d{2})\z~';

if (preg_match($pattern, $str, $m) && checkdate($m[2], $m[3], $m[1])) {
    // TRUE
} else {
    // FALSE
}

The advantage is that checkdate checks if the date exists (including cases of leap years). With this approach, there's no need to delegate more tasks to the regex part.

Casimir et Hippolyte
  • 88,009
  • 5
  • 94
  • 125
0

Anchors First

The most important thing in this validation is that you use the ^ and $ anchors to prevent a substring from matching in the middle of your input.

As for the regex, this is what I would suggest (assuming years start with a 1 or 2)

^([12][0-9]{3})-(0[1-9]|1[012])-([012][1-9]|[123]0|31)$

This regex demo tests the day part of the regex, while this other demo tests the month part.

Explanation

  • The ^ anchor asserts that we are at the beginning of the string
  • For the year, [12][0-9]{3} matches a 1 or 2 followed by three digits
  • For the month, (0[1-9]|1[012] matches 0 then 1 through 9, or 1 then 0, 1 or 2
  • For the day, [012][1-9]|[123]0|31 matches a 0, 1 or 2 followed by a digit from 1 to 9, or 1, 2 or 3 followed by a 0, or 31
  • The $ anchor asserts that we are at the end of the string
zx81
  • 41,100
  • 9
  • 89
  • 105
  • FYI: after tweaking added a [demo to test the month](http://regex101.com/r/dP1aZ8/3) part of the regex, and a [demo to test the day](http://regex101.com/r/dP1aZ8/4). – zx81 Jul 20 '14 at 23:54