简体   繁体   中英

Ruby Regular Expression to validate day and month of a date

On rubular I tested and confirmed that this does a good job confirming the desired format of a date entry:

\A\d\d\/\d\d\/\d\d\d\d\z

Tests:

01/02/2000 #pass
11/21/2014 #pass
11-21-2014 #fail
A3-21-2014 #fail

I want to make it a little bit better, and it will be good enough for me. What I want is to confirm that the "month field" (the first two digits) is anywhere from 01 - 12, where each single digit is led by a zero. (Ex: 01,02,03 etc as opposed to: 1,2,3).

Next: I want to do the same thing for the next two digits to confirm that the next two digits (the day field) is between 01 - 31. Same thing: Each single digit needs to lead with a zero.

Tests:

01/02/2017 #pass
12/31/2017 #pass
1/02/2017  #fail
01/2/2017  #fail
50/01/2017 #fail
01/50/2017 #fail

I realize that this regex will be inaccurate for those months that have fewer than 31 days, but it is good enough for what I am doing.

I considered deleting the question due to the down vote. I am choosing not to delete the question though because others might go down the same path as me, and I think I can provide a pretty good solution.

What I did was used the american_date gem. On your date inputs: the user should enter the date in the format of: "mm/dd/yyyy".

In order to force the user to enter the date in this format: I used jquery-inputmask-rails . I defined my mask like so:

$('.mask_american_date').inputmask({mask: "99/99/9999"});

Now there will be a nice mask on the date input that looks like this:

__/__/____

Now: all you need is a presence validator for the date field in your model:

validates_presence_of :date_of_birth, message: "Date is either invalid or is not present".

And this covers everything. How american date works is it takes the user input and attempts to convert it into a date. If it cannot convert the user input into a date for any reason: it will return nil which triggers the above validation.

  • This includes a bad month entry or a bad day entry. American Date is smart enough to know, for example, that September only has 30 days in it. So: if the user enters "31" for the day section, ex: 09/31/2017, american date will convert the date to nil .

Well this should get you most of the way there:

/((02\/[0-2]\d)|((01|[0][3-9]|[1][0-2])\/(31|30|[0-2]\d)))\/[12]\d{3}/

Granted it does not handle the following:

  • Leap Years eg 02/29 is acceptable regardless of the year
  • All Years from 1000-2999 are acceptable
  • Months with only 30 days eg 09/31 is acceptable

Small Breakdown in case links break:

Here is the runout on Rubular Here is an explanation from Regex101

  • (02\\/[0-2]\\d) - Starts with 02/ then allow 0-2 followed by 0-9
  • OR ((01|[0][3-9]|[1][0-2]\\/(31|30|[0-2]\\d)) - Starts with (01 or 0 followed by 3-9 or 1 followed by 0-2) followed a / followed by 31 or 30 or 0-2 followed by 0-9
  • In both cases must be followed by 1 or 2 followed by 3 digits 0-9

Really wish ruby supported look behind conditionals like true pcre Example for edification

As a Note : as mentioned in the comments rescuing a parsing failure is probably easier than using a regex but I figured since you asked.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM