I need help coming up with a regex to make sure the user enters a valid date
The string will be in the format of mm/dd/yyyy
Here is what I have come up
use DateTime;
Other solutions are fine, probably work, etc. Usually, you end up wanting to do a bit more, and then a bit more, and eventually you have some crazy code, and leap years, and why are you doing it yourself again?
DateTime and its formatters are your solution. Use them! Sometimes they are a bit overkill, but often that works out for you down the road.
my $dayFormat = new DateTime::Format::Strptime(pattern => '%d/%m/%Y');
my $foo = $dayFormat->parse_datetime($myDateString);
$foo
is now a DateTime object. Enjoy.
If your date string wasn't properly formatted, $foo
will be "undef"
and $dayFormat->errstr
will tell you why.
I have been working with this some time and the best regex I've came up with is the following:
\b(0)?(?(1)[1-9]|(3)?(?(2)[01]|[12][0-9]))\b|\b[1-9]\b
It will match the following numbers:
1 01 10 15 20 25 30 31
It does not match the following:
32 40 50 90
01-31
then RegEx is fine so long as there is some backend logic that validates the date as a whole, if so desired.I see the expected answer currently fails for 10, 20.
gawk 'BEGIN{ for(i=0;i<=32;i++){ if (i ~ /^([0-2]?[1-9]|3[01])$/){print i " yes"}else {print i " no"} } }
^([0-2]?[1-9]|3[01]|10|20)$
So kindly consider the following solution...
1. Identify the sets that need to be matched:
{01,...,09},{10,...,31}
{10,...,31}
can be split into => {10,...,29},{30,31}
{1,...,31} => {1,...,9},{10,...,31}
2. Corresponding regular expressions for each sub-set:
---------------------------------
Sub-Set | Regular-Expression
---------------------------------
{01,...,09} | [0][1-9]
{10,...,29} | [1-2][0-9]
{30,31} | 3[01]
{1,...,9} | [1-9]
---------------------------------
Now we can group ([0][1-9])
and ([1-9])
together as ([0]?[1-9])
. Where ?
signifies 0 or 1 occurrences of the pattern/symbol. [UPDATE] - Thank you @MattFrear for pointing it out.
So the resulting RegEx is: ^(([0]?[1-9])|([1-2][0-9])|(3[01]))$
Tested here: http://regexr.com/?383k1 [UPDATE]
^(((((((0?[13578])|(1[02]))[\.\-/]?((0?[1-9])|([12]\d)|(3[01])))|(((0?[469])|(11))[\.\-/]?((0?[1-9])|([12]\d)|(30)))|((0?2)[\.\-/]?((0?[1-9])|(1\d)|(2[0-8]))))[\.\-/]?(((19)|(20))?([\d][\d]))))|((0?2)[\.\-/]?(29)[\.\-/]?(((19)|(20))?(([02468][048])|([13579][26])))))$
From Expressions in category: Dates and Times
Validates the correct number of days in a month, looks like it even handles leap years.
You can of course change [\.\-/]
with /
to only allow slashes.