2

So I have this asp.net application built using razor and C# and I can't get the validation for date time to work correctly.
Here are the relevant sections of my app.

public class EmployeeDto
    {
    ...
    [Required]
    [DataMember]
    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MM/yyyy}")] // from what I understand this should format the date on the view ackording to the string
    public Nullable<DateTime> inDate { get; set; }

    ...

    [Required]
    [DataMember]
    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MM/yyyy}")]
    public Nullable<DateTime> birthDate { get; set; }

    [DataMember]
    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MM/yyyy}")]
    public Nullable<DateTime> createdDate { get; set; }
    ...
   }

This DTO is also used as a view model.

On the add employee view, we use a date-picker to edit the first two dates. The third is hidden.

Here's what the view looks like

 @model StratecEMS.Application.DTO.EmployeeDto
 <style type="text/css">...</style>
 <script type="text/javascript">
$(function () {
    $("#birthDate").datepicker({ dateFormat: 'dd/mm/yy' });
    $("#inDate").datepicker({ dateFormat: 'dd/mm/yy' });
});
...
</script>
...
<fieldset>
    <legend>New Employee Details</legend>
    @using (Html.BeginForm("AddEmployee", "Administration", FormMethod.Post, new { id = "AddEmployeeForm" }))
    {
        @Html.HiddenFor(model => Model.createdDate)
        <div class="editor-label">
            @Html.Label("In Date:")
            @Html.EditorFor(model => model.inDate)
            @Html.ValidationMessageFor(model => model.inDate)
        </div>
        <div class="editor-label">
            @Html.Label("Birthdate:")
            @Html.EditorFor(model => model.birthDate)
            @Html.ValidationMessageFor(model => model.birthDate)
        </div>
     }
  </fieldset>

Now here's my problem: On my PC I have the date in international format "yyyy-MM-dd". On the application we need the date to always be in a custom format "dd/MM/yyyy" however the validation is always done in the US format "MM/dd/yyyy" and I'm at a loss why this happens.

To make things even stranger after adding the DisplayFormat attribute to the DTO, the two dates that are displayed on my UI are shown in this format "dd-MM-yyyy". WTF!?! but the validation is sill done in the US format.

I can get around the validation for the birthDate and inDate by entering the dates in the US format in the text-boxes, however there is no such workaround for createdDate which is always hidden and remains in the in the international format.

I've also tried to change the culture of the application by setting the thread culture in the Global.asax Application_Start method using this piece of code

var culture = (CultureInfo)CultureInfo.CurrentCulture.Clone();
culture.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy";
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture; 

However this too seems not to work.

If you had the patience to read this until the end. Do you happen to know a good solution for this predicament?

VMAtm
  • 27,943
  • 17
  • 79
  • 125
memory of a dream
  • 1,207
  • 3
  • 23
  • 32

3 Answers3

2

The problem with this behaviour is that the / symbol is used in Custom DateTime formatting as the separator.

So, then you view the date times on your machine, the .NET framework replaces the dd/MM/yyyy with dd-MM-yyyy. So you can try to override the datetime separator symbol, as you tried with ShortDatePattern, or you can escape the / symbol in the format string, like this: dd'/'MM'/'yyyy, but I can't try it out right now.


Update:

From MSDN

To change the date separator for a particular date and time string, specify the separator character within a literal string delimiter. For example, the custom format string mm'/'dd'/'yyyy produces a result string in which / is always used as the date separator.

To change the date separator for all dates for a culture, either change the value of the DateTimeFormatInfo.DateSeparator property of the current culture, or instantiate a DateTimeFormatInfo object, assign the character to its DateSeparator property, and call an overload of the formatting method that includes an IFormatProvider parameter.

So you should try this:

Thread.CurrentThread.CurrentCulture.DateTimeFormatInfo.DateSeparator = '/';
Thread.CurrentThread.CurrentUICulture.DateTimeFormatInfo.DateSeparator = '/';

And @Givan is right:

Validation is likely happening on your server. Therefore the date format specified on the server will be used. This is perhaps why MM/dd/yyyy is always used.

VMAtm
  • 27,943
  • 17
  • 79
  • 125
  • 1
    Well that's part of the solution. I managed to set the culture for controller thread in it's constructor :( the code in Global.asax doesn't seem to have the desired effect. Validation now works perfectly for the dates displayed on the UI, but the string for the hidden date is still returned by the view in the "yyyy-MM-dd" format. And is validated in my custom format. – memory of a dream Dec 29 '14 at 14:02
  • 1
    I've finally decided to replace the `@Html.HiddenFor(model => Model.createdDate)` with a hidden div `` and everything works fine – memory of a dream Dec 30 '14 at 11:03
1

You can specify custom model binder based on DataFormatString in DisplayFormatAttribute

public class DateFormatBinding : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        string displayFormat = bindingContext.ModelMetadata.DisplayFormatString;
        ValueProviderResult value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

        if (!string.IsNullOrEmpty(displayFormat) && value != null)
        {
            DateTime date;
            displayFormat = displayFormat.Replace("{0:", string.Empty).Replace("}", string.Empty);
            // use the format specified in the DisplayFormat attribute to parse the date
            if (DateTime.TryParseExact(value.AttemptedValue, displayFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out date))
            {
                return date;
            }

            bindingContext.ModelState.AddModelError(bindingContext.ModelName, string.Format("{0} is an invalid date format", value.AttemptedValue));
        }

        return base.BindModel(controllerContext, bindingContext);
    }
}

Add it to project, and then register in Global.asax

protected void Application_Start()
{
   ...
   ModelBinders.Binders.Add(typeof(DateTime), new DateFormatBinding());
   ModelBinders.Binders.Add(typeof(DateTime?), new DateFormatBinding());
   ...
}
offi
  • 380
  • 8
  • 13
0

I guess it's IIS you're running. If so have a look at this: IIS VS 2008 / Web.config - wrong date format

Perhaps this is also helpful. How to set Date and time format in IIS 7

Community
  • 1
  • 1
Giwan
  • 1,564
  • 14
  • 17