I'm currently working on an ASP.NET MVC 4 website using unobtrusive jquery validation. My browser of choice is Chrome. In my app I have a required Date of Birth. ASP.NET MVC 4 hooks up the client side validation for me and whenever I enter a date in dd/mm/yyyy format that is not a valid date in mm/dd/yyyy fomat I get an error (eg 19/11/2012 - there is no 19th month).
To validate a date the jQuery validation plugin simply tries to call new Date(myDateString), as seen here;
// http://docs.jquery.com/Plugins/Validation/Methods/date
date: function(value, element) {
return this.optional(element) || !/Invalid|NaN/.test(new Date(value));
},
See line 1098 in jquery.validate.js.
I need something a little more robust, so I created a parser.
function getDateFormat(formatString) {
var separator = formatString.match(/[.\/\-\s].*?/),
parts = formatString.split(/\W+/);
if (!separator || !parts || parts.length === 0) {
throw new Error("Invalid date format.");
}
return { separator: separator, parts: parts };
}
function MyParseDate(date, format) {
var parts = date.split(format.separator),
date = new Date(),
val;
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);
date.setMilliseconds(0);
if (parts.length === format.parts.length) {
console.log(parts.length);
for (var i = 0, cnt = format.parts.length; i < cnt; i++) {
val = parseInt(parts[i], 10) || 1;
switch (format.parts[i]) {
case 'dd':
case 'd':
date.setDate(val);
break;
case 'mm':
case 'm':
date.setMonth(val);
break;
case 'yy':
date.setFullYear(2000 + val);
break;
case 'yyyy':
date.setFullYear(val);
break;
}
}
}
return date;
}
In the above I am building up the date based on the value and format passed into MyParseDate. I’m going to always pass in a format of “dd/mm/yyyy” in my current locale, but I want that to change based on where the user is. getDateFormat() takes a date format string.
Then I need to override the jquery validation code with my own.
jQuery.validator.addMethod('date',
function (value, element, params) {
if (this.optional(element)) {
return true;
}
var result = false;
try {
var format = getDateFormat('dd/mm/yyyy');
MyParseDate(value, format);
result = true;
} catch(err) {
console.log(err);
result = false;
}
return result;
});
You’ll need to put in every page that uses dates. I’m using ASP.NET MVC 4 so I decided to add it to my jquery validator bundle, so I can be sure that wherever I’m using jquery validators, I’m getting my date validator. I also called the above method from $(document).ready();
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.unobtrusive*",
"~/Scripts/jquery.validate*",
"~/Scripts/custom.jquery.validate.js"));
To be fair, the RFC does say only ISO dates should be converted, which Chrome does do. What is alarming is that IE 10 (as tested on my Windows 8 machine) handles new Date('19/11/2012') and new Date('11/19/2012'). I wonder what month I'll get on IE :S