views:

969

answers:

6

Hi,
I am getting a date field from the database in one of my variables, at the moment I am using the following code to check if the date is in "yyyy-mm-dd" format

if ( $dat =~ /\d{3,}-\d\d-\d\d/ )

My question, is there a better way to accomplish this.

Many Thanks

+2  A: 

\d could match number characters from other languages. And is YYY really a valid year? If it must be four digits, dash, two digits, dash, two digits, I'd prefer /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/ or /^[12][0-9]{3}-[0-9]{2}-[0-9]{2}$/. Be aware of space characters around the string you're matching.

Of course, this doesn't check the reasonableness of the characters that are there, except for the first character in the second example. If that's required, you'll do well to just pass it to a date parsing module and then check its output for logical results.

Anonymous
+1  A: 

Well you can start with:

/\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|30|31)/
Igor Oks
+1  A: 

How about

/\d{2}\d{2}?-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])/
toolkit
+4  A: 

The OWASP Validation Regex Repository's version of dates in US format with support for leap years:

^(?:(?:(?:0?[13578]|1[02])(\/|-|.)31)\1|(?:(?:0?[1,3-9]|1[0-2])(\/|-|.)(?:29|30)\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:0?2(\/|-|.)29\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:(?:0?[1-9])|(?:1[0-2]))(\/|-|.)(?:0?[1-9]|1\d|2[0-8])\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$

The Regular Expression Library contains a simpler version along the lines of the other suggestions, which is translated to your problem:

^\d{4}-\d{1,2}-\d{1,2}$
wr
+2  A: 

As noted by others, if this is a date field from a database, it should be coming in a well-defined format, so you can use a simple regex, such as that given by toolkit.

But that has the disadvantage that it will accept invalid dates, such as 2009-02-30. Again, if you're handling dates that successfully made it into a date-typed field in a DB, you should be safe.

A more robust approach would be to use one of the many Date/Time modules from CPAN. Probably Date::Manip would be a good choice, and in particular check out the ParseDate() function.

http://search.cpan.org/~sbeck/Date-Manip-5.54/lib/Date/Manip.pod

Elbin
A: 

I would very strongly recommend AGAINST writing your own regular expression to do this. Date/time parsing is simple, but there are some tricky aspects, and this is a problem that has been solved hundreds of times. No need for you to design, write, and debug yet another solution.

If you want a regular expression, the best solution is probably to use my Regexp::Common::time plugin for the Regexp::Common module. You can specify simple or complex, rigid or fuzzy date/time matching, and it has a very extensive test suite.

If you just want to parse specific date formats, you may be better off using one of the many parsing/formatting plugins for Dave Rolsky's excellent DateTime module.

If you want to validate the date/time values after you have matched them, I would suggest my Time::Normalize module.

Hope this helps.