Here's one possible regex:
^\d{4}-((0\d)|(1[012]))-(([012]\d)|3[01])$
Note: this will prevent months >12 and days >31, but won't check specific months for length (ie it won't block 30th Feb or 31st Apr). You could write a regex to do that, but it would be quite lengthy, and 29th Feb is always going to give you problems in regex.
I'd say if you need that kind of fine-grained validation, you're better off parsing the date with a date library; regex isn't the tool for you. This regex should be sufficient for basic pre-validation though.
I've also gone lenient on the year; just checking that it's four digits. But if you want some sort of sanity check (ie within certain bounds), it shouldn't be too hard to add. Foe example, if you want to match only dates in the this century, you would replace the \d{4}
at the beginning of the regex with 20\d{2}
. Again, trying to validate a date with excessive accuracy in regex is going to be difficult and you should use a date parser, but you can get basic century-level matching quite easily to prevent the user entering anything really silly.
Finally, I've put ^
and $
to tie off the ends of the string so it can't match if the user enters a valid date and extra characters as well. (You may want to add a string length validator for this as well).
Hope that helps.