jQuery Validation – Dates, “Say, What?”

A “bug” for jQuery Date validation, how could that be?

Recently, an unusual “bug” was reported by our QA Team.  The bug was for field validation for a DateTime property.   The implementation was nothing special, just the standard MVC implementation we’ve all seen time & time again.

[Required]
public DateTime? DateOfBirth { get; set; }

<input Value="" data-val="true" data-val-date="The field Date of Birth must be a date." data-val-required="The Date of Birth field is required." id="DateOfBirth" name="DateOfBirth" type="text" value="" />

The bug was reported that the values “13/30/1980 and 12/35/1980” were entered and a validation error message was NOT displayed.  It turns out the server side check was working, so we were ok, but what about the client validation??

jQuery Validation Date Method

Well, after isolating the scenario and eliminating all variables, the “bug” still exists.  Hmmm… maybe there is a bug in the version we are using….nope.  Here is the answer straight from the horse’s mouth (jQuery Validation Date Method Documentation):

Return true if the value is a valid date. Uses JavaScript’s built-in Date to test if the date is valid, and therefore does no sanity checks. Only the format must be valid, not the actual date, eg 30/30/2008 is a valid date.

This method should not be used, since it relies on the new Date constructor, which behaves very differently across browsers and locales. Use dateISO instead or one of the locale specific methods (in localizations/ and additional-methods.js).

The Property is of type DateTime, so the standard MVC implementation is to add the data-val-date attribute to the input.  The jQuery Validation picks up the attributes and executes the jQuery Validation Date function…and here is the function in jquery.validate.js

// http://docs.jquery.com/Plugins/Validation/Methods/date
date: function( value, element ) {
return this.optional(element) || !/Invalid|NaN/.test(new Date(value).toString());
}

How can have a better client-side experience?

There are several solutions some more complex than others, depending on your need for localization.  Here is a simple solution to override the jQuery Validation Date function, just load this script after your jQuery Validation scripts.

This function checks a few things:

  • Is the Format valid, accepting a few formats:
    • m-d-yyyy, m-dd-yyyy, mm-d-yyyy, mm-dd-yyyy
    • m/d/yyyy, m/dd/yyyy, mm/d/yyyy,  mm/dd/yyyy
    • Is the month 1-12
    • Is the day 1-31
    • If April, June, September or November, then only 30 days (not 31)
    • Is it a leap year, if so, then no February 29th
$(function () {
    $.validator.methods.date = function (value, element) {
        return this.optional(element) || isDate(value);
    }
});

// ******************************************************************
// This function accepts a string variable and verifies if it is a
// proper date or not. It validates format matching either
// mm-dd-yyyy or mm/dd/yyyy. Then it checks to make sure the month
// has the proper number of days, based on which month it is.

// The function returns true if a valid date, false if not.
// ******************************************************************

function isDate(dateString) {
    var isValid = true;
    var datePattern = /^(\d{1,2})(\/|-)(\d{1,2})(\/|-)(\d{4})$/;
    var matchArray = dateString.match(datePattern); // is the format ok?

    if (matchArray == null) {
        isValid = false;
    } else {
        month = matchArray[1]; // parse date into variables
        day = matchArray[3];
        year = matchArray[5];

        if (month < 1 || month > 12) { // check month range
            isValid = false;
        }

        if (day < 1 || day > 31) {
            isValid = false;
        }

        if ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) {
            isValid = false;
        }

        if (month == 2) { // check for February 29th
            var isleap = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
            if (day > 29 || (day == 29 && !isleap)) {
                isValid = false;
            }
        }
    }
    return isValid;
}

Further Reading

http://jqueryvalidation.org/date-method

http://stackoverflow.com/questions/6906725/unobtrusive-validation-in-chrome-wont-validate-with-dd-mm-yyyy

Nate Bunton

Nate Bunton is a Lead Software Engineer at Meta Payment Systems. He has over 10 years developing software and leading teams. He works with the Microsoft technology stack focusing in ASP.NET, MVC, HTML, JavaScript, CSS and Web Security. Nate also focuses on Application Lifecycle Management (ALM) engaging his teams with key stakeholders using a variety of agile principals. At Meta Payment Systems, Nate has been a leader in driving technology in the enterprise from new Web Technology to Service Oriented Architecture using WCF and NServiceBus. Nate’s greatest passion is for User Experience, Web Technology and Engaging Teams. He is driven by his desire for continuous learning & improvement.

Posted in Web Development Tagged with: , , , ,