Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Regex to match Date

Tags:

regex

ruby

I want to match dates with format mm/dd/yy or mm/dd/yyyy but it should not pick 23/09/2010 where month is 23 which is invalid nor some invalid date like 00/12/2020 or 12/00/2011.

like image 477
Lohith MV Avatar asked May 12 '11 13:05

Lohith MV


Video Answer


2 Answers

Better than a crazy huge Regex (assuming this is for validation and not scanning):

require 'date'
def valid_date?( str, format="%m/%d/%Y" )
  Date.strptime(str,format) rescue false
end

And as an editorial aside: Eww! Why would you use such a horribly broken date format? Go for ISO8601, YYYY-MM-DD, which is a valid international standard, has a consistent ordering of parts, and sorts lexicographically as well.

like image 94
Phrogz Avatar answered Sep 25 '22 14:09

Phrogz


You'd better do a split on / and test all individual parts. But if you really want to use a regex you can try this one :

#\A(?:(?:(?:(?:0?[13578])|(1[02]))/31/(19|20)?\d\d)|(?:(?:(?:0?[13-9])|(?:1[0-2]))/(?:29|30)/(?:19|20)?\d\d)|(?:0?2/29/(?:19|20)(?:(?:[02468][048])|(?:[13579][26])))|(?:(?:(?:0?[1-9])|(?:1[0-2]))/(?:(?:0?[1-9])|(?:1\d)|(?:2[0-8]))/(?:19|20)?\d\d))\Z#

Explanation:

\A           # start of string
 (?:         # group without capture
             # that match 31st of month 1,3,5,7,8,10,12
   (?:       # group without capture
     (?:     # group without capture
       (?:   # group without capture
         0?  # number 0 optionnal
         [13578] # one digit either 1,3,5,7 or 8
       )     # end group
       |     # alternative
       (1[02]) # 1 followed by 0 or 2
     )       # end group
     /       # slash
     31      # number 31
     /       # slash
     (19|20)? #numbers 19 or 20 optionnal
     \d\d    # 2 digits from 00 to 99 
   )         # end group
|
   (?:(?:(?:0?[13-9])|(?:1[0-2]))/(?:29|30)/(?:19|20)?\d\d)
|
   (?:0?2/29/(?:19|20)(?:(?:[02468][048])|(?:[13579][26])))
|
   (?:(?:(?:0?[1-9])|(?:1[0-2]))/(?:(?:0?[1-9])|(?:1\d)|(?:2[0-8]))/(?:19|20)?\d\d)
 )
\Z

I've explained the first part, leaving the rest as an exercise.

This match one invalid date : 02/29/1900 but is correct for any other dates between 01/01/1900 and 12/31/2099

like image 35
Toto Avatar answered Sep 21 '22 14:09

Toto