1

My model class property looks like this

   public DateTime PurchaseDate { get; set; }

and inside view

 @Html.TextBoxFor(model => model.PurchaseDate, new { @class = "form-control date-picker" })
 @Html.ValidationMessageFor(model => model.PurchaseDate)

and I am giving a date like this in form

19/06/2015

But it gives validation message and not allows page to be submitted, message is like this

The field PurchaseDate must be a date.

if I give date in mm/dd/yyyy format it works. Can anyone point out what I am doing wrong here?

None
  • 5,582
  • 21
  • 85
  • 170
  • You can use `jquery.globalize` or override the jquery validator for date as per [this answer](http://stackoverflow.com/questions/27285458/jquery-ui-datepicker-and-mvc-view-model-type-datetime/27286969#27286969) –  Jun 02 '15 at 11:00
  • You can give format in Model. – Mairaj Ahmad Jun 02 '15 at 11:02
  • @StephenMuecke tried not working – None Jun 02 '15 at 11:06
  • Which one? Which date picker are you using? –  Jun 02 '15 at 11:08
  • @StephenMuecke bootstrap datepicker http://www.eyecon.ro/bootstrap-datepicker/ – None Jun 02 '15 at 11:17
  • That datepicker appears to have a very limited api and nothing that parses the date. Have you tried using `jquery.globalize.js`? - the code would be something like `$.validator.addMethod('date', function (value, element) { Globalize.culture("en-GB"); return this.optional(element) || Globalize.parseDate(value) !== null; }` –  Jun 02 '15 at 11:28
  • @StephenMuecke can't change whole plugin now :( – None Jun 02 '15 at 11:43
  • Just as a test, try `$.validator.addMethod('date', function (value, element) { return true; }` –  Jun 02 '15 at 11:49
  • @StephenMuecke Yes you are right, That works. If you could add it as answer with detail. That will be helpful for others too – None Jun 02 '15 at 11:54
  • That's not the answer - it was just to test to make sure you had the script correct (the `return true;` statement means you could enter/select anything). But I do have some code at work that will correctly validate this but wont be able to post it until tomorrow. –  Jun 02 '15 at 11:58

2 Answers2

3

The client side error is occurring because by default jquery.validate tests the value using the MM/dd/yyyy format. You can override the $.validator.addMethod('date', function (value, element) function to test that the value is in the dd/MM/yyyy you expect. Note the following code is from my own jquery plugin associated with a @Html.DatePickerFor() helper method which renders a data-dateformat attribute in the output based on the servers culture, so it may be an overkill for your needs

Add the following scripts (not in document.ready, but after jquery.validate.unobtrusive)

Date.prototype.isValid = function () {
  return !isNaN(this.getTime());
}

globalDate = function (value, formatString) {
  // Initialise a new date
  var date = new Date(0);
  if (value == undefined) {
    // Return todays date
    return date;
  }
  // Get the components of the format
  // The separator can be forward slash, hyphen, dot and/or space
  var regex = new RegExp(/([dMy]+)([\s/.-]+)([dMy]+)([\s/.-]+)([dMy]+)/);
  //var format = regex.exec(this.inputFormat);
  var format = regex.exec(formatString);
  // Get the components of the value
  regex = new RegExp(/(\d+)([\s/.-]+)(\d+)([\s/.-]+)(\d+)/);
  value = regex.exec(value);
  // Check the value is valid
  if (value === null || value[2] !== format[2] || value[4] !== format[4]) {
    // Its not valid
    date.setTime(Number.NaN);
    return date;
  }
  // TODO: What if year entered as 2 digits?
  var day = Number.NaN;
  var month = Number.NaN;
  var year = Number.NAN;
  if (format[1].charAt(0) === 'd') {
    // little-endian (day, month, year)
    day = parseInt(value[1]);
    month = parseInt(value[3]) - 1;
    year = parseInt(value[5]);
  } else if (format[1].charAt(0) === 'M') {
    // middle-endian (month, day, year)
    day = parseInt(value[3]);
    month = parseInt(value[1]) - 1;
    year = parseInt(value[5]);
  } else {
    // big endian (year, month, day)
    day = parseInt(value[5]);
    month = parseInt(value[3]) - 1;
    year = parseInt(value[1]);
  }
  date.setFullYear(year);
  date.setMonth(month);
  date.setDate(day);
  // Check its valid
  if (date.getDate() !== day || date.getMonth() !== month || date.getFullYear() !== year) {
    date.setTime(Number.NaN);
    return date;
  }
  return date;
}

$.validator.addMethod('date', function (value, element) { 
  var format = "dd/MM/yyyy";
  return this.optional(element) || globalDate(value, format).isValid();
}

If you only ever want to test for the format dd/MM/yyyy, then you could simplify the globalDate() function by just using

var date = new Date();
date.setHours(0, 0, 0, 0);
var components = value.split('/');
var day = components[0];
var month = components[1];
var year = components[2];
date.setFullYear(year);
....

Edit

Further to OP's comments regarding server side validation failing, the server culture needs to accept a date string in the format dd/MM/yyyy. In the web.config.cs file

<system.web>
  <globalization culture="en-AU" uiCulture="en-AU"/> // adjust to your culture code
  ....
  • this removes client side error message but gives me an error message at my modestate validation in server side like this "The value '26/06/2015' is not valid for PurchaseDate.". – None Jun 03 '15 at 05:19
  • my model element is like this now [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)] public DateTime PurchaseDate { get; set; } – None Jun 03 '15 at 05:19
  • Note the `[DisplayFormat]` attribute is pointless in your case. Its only respected when using `@Html.DisplayFor()` or `@Html.EditorFor()`. In `TextBoxFor()` its ignored. If you are getting the error server side its because you server culture does not accept a date in the format `dd/MM/yyyy`. You will need to set the culture in the `web.config.cs` file - see my edit to the answer –  Jun 03 '15 at 05:42
2

If you want to explicitly set the expected date format for your model property then you can do this using the DisplayAttribute

[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
public DateTime PurchaseDate { get; set; }

Otherwise, the current culture of the server would be used (which in your case happens to be MM/dd/yyyy).


It appears that in order for client-side validation to respect the DataFormatString we need to use EditorFor in place of TextBoxFor

 @Html.EditorFor(model => model.PurchaseDate, new { @class = "form-control date-picker" })
 @Html.ValidationMessageFor(model => model.PurchaseDate)
James
  • 80,725
  • 18
  • 167
  • 237
  • I have tried this, But I am still getting same message – None Jun 02 '15 at 11:15
  • @Athul what sort of error are you getting though? Is it client-side or server side? – James Jun 02 '15 at 11:45
  • Same as I said in my question there is no change in error, It is client side – None Jun 02 '15 at 11:48
  • @Athul try using `EditorFor` rather than `TextBoxFor`, I think the problem is `TextBoxFor` does not respect the `DisplayFormat` attribute. – James Jun 02 '15 at 12:33
  • @James, OP's issue is related to jquery client side validation (when posting), not the format when rendering the value. –  Jun 02 '15 at 23:22