1

I have some code for validating date below:


function validateForm() {
var errFound = 0;       
//var patt_date = new RegExp("^((((19|20)(([02468][048])|([13579][26]))-02-29))|((20[0-9][0-9])|(19[0-9][0-9]))-((((0[1-9])|(1[0-2]))-((0[1-9])|(1\d)|(2[0-8])))|((((0[13578])|(1[02]))-31)|(((0[1,3-9])|(1[0-2]))-(29|30)))))$");
var patt_date = new RegExp("^[0-9]{4}-(((0[13578]|(10|12))-(0[1-9]|[1-2][0-9]|3[0-1]))|(02-(0[1-9]|[1-2][0-9]))|((0[469]|11)-(0[1-9]|[1-2][0-9]|30)))$");
if (patt_date.test(document.getElementById("datefrom").value) == false){errFound = errFound + 1;document.getElementById("datefrom").className = "error";}

if (errFound > 0)
    alert('Please correct red colored field!');
else
    return true;
return false;   
}


Above code should work with YYYY-MM-DD format, but fail to validate date such as "2009-02-29"

The commented code should work (//var patt_date = new RegExp...), it can catch "2009-02-29",
but it ruin the validation when i put invalid data and try to correct it, it keeps complain there something wrong with form value after i had correct them (especially on form with multiple input)

Maybe someone can fix the current regex?


Edited, what i want just a simple replacement for above regexp, mean a new regexp pattern not the whole new method to validate date
And for reference, i simply grab the regexp pattern from:
http://www.regexlib.com/REDetails.aspx?regexp_id=694 and
http://www.regexlib.com/REDetails.aspx?regexp_id=933

Tested with 2009-02-29, 1st link work & 2nd not. Again the problem was only the 2nd regexp didn't detect value 2009-02-29 as invalid while 1st can (but it ruin my code? so it's must be there something wrong with it).

Thanks,
Dels

Dels
  • 2,375
  • 9
  • 39
  • 59
  • Can you give an example of a date that the second regexp should match but does not? Also your first (commented out) regexp is slightly wrong with respect to leap days - it assumes that 1900 was a leap year when it was not. – Tyler McHenry Mar 19 '09 at 05:10

3 Answers3

8

Don't do the whole date validation with a regular expression, that's really pushing the limits of what regexps were designed for. I would suggest this procedure instead:

  1. Check date against regexp /^\d{4}-\d{2}-\d{2}$/
  2. Extract year, month, and day using substr() and convert to integers
  3. Use some if statements to validate the integers. Like so:
    if (month == 2) {
        if (day == 29) {
            if (year % 4 != 0 || year % 100 == 0 && year % 400 != 0) {
                // fail
            }
        }
        else if (day > 28) {
            // fail
        }
    }
    else if (month == 4 || month == 6 || month  == 9 || month == 11) {
        if (day > 30) {
            // fail
        }
    }
    else {
        if (day > 31) {
            // fail
    }

(That could certainly be written more concisely) Alternatively, you could probably perform this validation using Javascript's Date class - you might have to do something like parsing the date, converting it back to a string, and checking if the two strings are equal. (I'm not a Javascript expert)

David Z
  • 128,184
  • 27
  • 255
  • 279
  • And you can give the user a useful error message, like: "February has only XX days". – Aaron Digulla Mar 19 '09 at 09:12
  • but i'm not expert on JS Stuff... can't think what more fast & easy then creating a regexp LOL – Dels Mar 19 '09 at 09:32
  • Love this approach, but the series of tests need to be extended slightly so the value of month is also tested. A value of '13/30/2012' would be valid otherwise. – Thomas Aug 30 '12 at 16:11
3

I kinda agree with David on this... Regex matches should not be used as an exclusive criterion to decide if the passed date is, in fact, valid. The usual procedure in Javascript validation involves a few steps :

a. The first step is to ensure that the passed string matches expected date formats by matching it against a Regex. The following may be a stricter Regex pattern.

// Assuming that the only allowed separator is a forward slash.
// Expected format: yyyy-mm-dd
/^[12][90][\d][\d]-[0-3]?[\d]-[01]?[\d]$/

b. The second step is to parse the string into a Date object which returns the no. of milliseconds since 1970. Use this number as a parameter for the Date constructor.

c. Since JS automatically rolls over the passed date to the nearest valid value, you still cannot be certain if the Date object created matches that which was passed. To determine if this happened, the best way is to split the passed string according to the separator and compare individual date components:

// d is the created Date object as explained above.
var arrDateParts = inputDate.split("-");
if ((d.getFullYear() == arrDateParts[0]) && (d.getMonth() == arrDateParts[1]) && (d.getDate() == arrDateParts[2]))
  return true;
else
  return false;
Cerebrus
  • 25,615
  • 8
  • 56
  • 70
  • Hi! In your test in part c, you should add one to d.getMonth() -- the return value is in the range 0-11, and the inputDate probably has the month in the range 01-12. – Ricky Morse May 12 '11 at 19:11
-1

This javascript code validates date exactly. You can copy it and test it in your browser.

 var regDate = '^(19[0-9]{2}|2[0-9]{3})-(0[1-9]{1}|1[0-2]{1}){1}-(0[1-9]|(1|2)[0-9]|3[0-1]){1}$';
 var txt='2010-01-31';
 if(txt.match(regDate))
 {
    alert('date match');
 }
HoLyVieR
  • 10,985
  • 5
  • 42
  • 67
Yosri
  • 1