205

I'm using the DataType.Date attribute on my model and an EditorFor in my view. This is working fine in Internet Explorer 8 and Internet Explorer 9, but in Google Chrome it is showing a date picker and instead of displaying the value it just displays "Month/Day/Year" in faded gray text.

Why won't Google Chrome display the value?

Model:

[DataType(DataType.Date)]
public Nullable<System.DateTime> EstPurchaseDate { get; set; }

View:

<td class="fieldLabel">Est. Pur. Date</td>
<td class="field">@Html.EditorFor(m=>m.EstPurchaseDate)</td>

Chrome

Internet Explorer

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ben Finkel
  • 4,753
  • 7
  • 34
  • 49

8 Answers8

393

When you decorate a model property with [DataType(DataType.Date)] the default template in ASP.NET MVC 4 generates an input field of type="date":

<input class="text-box single-line" 
       data-val="true" 
       data-val-date="The field EstPurchaseDate must be a date."
       id="EstPurchaseDate" 
       name="EstPurchaseDate" 
       type="date" value="9/28/2012" />

Browsers that support HTML5 such Google Chrome render this input field with a date picker.

In order to correctly display the date, the value must be formatted as 2012-09-28. Quote from the specification:

value: A valid full-date as defined in [RFC 3339], with the additional qualification that the year component is four or more digits representing a number greater than 0.

You could enforce this format using the DisplayFormat attribute:

[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public Nullable<System.DateTime> EstPurchaseDate { get; set; }
Colin
  • 22,328
  • 17
  • 103
  • 197
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • 44
    Darin thank you, that was perfect! You've answered so many of my MVC questions over the past two years, you rock! – Ben Finkel Sep 28 '12 at 14:48
  • 3
    Great answer but I feel this is appealing you have to force it just to get the control to work properly! – Paul C May 16 '13 at 17:33
  • 7
    What would be the way of doing this "globally" for all properties marked `[DataType(DataType.Date)]` so I wouldn't have to mark all these properties separately with the risk of missing some? – Marjan Venema Jul 20 '13 at 13:35
  • 7
    Darin, What can us people outside USA do? How can I set the specification value but display a custom date format? ie, UK? – Piotr Kula Apr 15 '14 at 20:57
  • 2
    @ppumkin: This is not US specific. In fact, the reason the HTML5 specification uses `YYYY-MM-DD` is because it's an international standard (ISO 8601). If you need to display the date in a different format, you'll need to utilize view models in your views so that you can set the date format for your form to ISO 8601, but set the date format for something like a detail view to whatever the localized version you desire is. – Chris Pratt Jun 26 '14 at 15:16
  • 2
    The format displayed in Chrome is whatever is set in your systems globalization settings. So, yes, set everything as per example in ISO 8601 but make sure the system is set to the correct Globale. After chaining it make sure to restart Chrome, Firefox.. not sure about IE or other browsers. – Piotr Kula Jul 01 '14 at 11:15
  • 2
    @MarjanVenema - I've hooked into the Model Metadata and I add this to the DisplayFormatString and to the EditFormatString. – SwampyFox Jul 29 '14 at 01:07
  • @SwampyFox: Thanks! (Any references on how to do this?) – Marjan Venema Jul 29 '14 at 17:33
  • 3
    @MarjanVenema- I've used the "ExtensibleModelMetadataProvider" from Matt Honeycutt's FailTracker (https://github.com/MattHoneycutt/Fail-Tracker). Look under the Infrastructure Folder to the ModelMetadata. I've used those classes and then created an filter implementation of IModelMetadataFilter. When the TransformMetadata method is called, you can then edit the "DisplayFormatString" and "EditFormatString" properties of the metadata. Hope this gets you in the right direction (btw, there is a great pluralsight video that uses Fail-Tracker) – SwampyFox Jul 30 '14 at 19:26
  • Its not working for me. Year part in date picker accepting upto 6 digits. How can i restrict to 4 digits. Heres my code : [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)] [DataType(DataType.Date, ErrorMessage = "Please enter a valid date in the format MM/DD/YYYY")] [Display(Name = "Date of Birth:")] [Required] public string DOB { get; set; } – Rahul Nikate Jan 22 '15 at 16:08
  • Maaann, i was searching for this and I finally got it! thank you!! – MelloG Mar 12 '18 at 19:33
  • Great answer! I had the same problem with 0:MM/dd/yyyy instead of the other way around - 0:yyyy-MM-dd. This worked (the commented-out annotations is what I originally had in my model:`[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)] //[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)] [DataType(DataType.Date)]` – Greg Barth Oct 22 '20 at 20:59
45

In MVC5.2, add Date.cshtml to folder ~/Views/Shared/EditorTemplates:

@model DateTime?
@{
    IDictionary<string, object> htmlAttributes;
    object objAttributes;
    if (ViewData.TryGetValue("htmlAttributes", out objAttributes))
    {
        htmlAttributes = objAttributes as IDictionary<string, object> ?? HtmlHelper.AnonymousObjectToHtmlAttributes(objAttributes);
    }
    else
    {
        htmlAttributes = new RouteValueDictionary();
    }
    htmlAttributes.Add("type", "date");
    String format = (Request.UserAgent != null && Request.UserAgent.Contains("Chrome")) ? "{0:yyyy-MM-dd}" : "{0:d}";
    @Html.TextBox("", Model, format, htmlAttributes)
}
Charlie
  • 1,265
  • 15
  • 18
  • thanks! fixes the mentioned chrome "issue" and of course you can have another displayformat on your datetime property! – cmxl Mar 24 '15 at 19:09
  • Yes great solution. This provides an excellent work around for those of us not in the US. – Richard McKenna Aug 28 '15 at 14:33
  • I think this is the best solution to the problem, it fixes just the editor issue and doesn't affect existing display formatting. – dsghi Sep 23 '15 at 10:40
  • 1
    Using "Date.cshtml" instead of "DateTime.cshtml" was the magic answer! It works in MVC 4 as well. – Atron Seige Oct 22 '15 at 12:56
  • Had to stick with `DateTime.cshtml` instead of the recommended `Date`, but after a couple tweaks it worked great! One of my key changes was using the pre-formatted value (generated using the model property's specified DisplayFormat), which made the last line: `@Html.TextBox(ViewData.TemplateInfo.HtmlFieldPrefix, ViewData.TemplateInfo.FormattedModelValue, htmlAttributes)` – brichins Dec 20 '18 at 22:58
19

As an addition to Darin Dimitrov's answer:

If you only want this particular line to use a certain (different from standard) format, you can use in MVC5:

@Html.EditorFor(model => model.Property, new {htmlAttributes = new {@Value = @Model.Property.ToString("yyyy-MM-dd"), @class = "customclass" } })
Arjan
  • 16,210
  • 5
  • 30
  • 40
11

In MVC 3 I had to add:

using System.ComponentModel.DataAnnotations;

among usings when adding properties:

[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]

Especially if you are adding these properties in .edmx file like me. I found that by default .edmx files don't have this using so adding only propeties is not enough.

Azoro
  • 391
  • 3
  • 7
10

If you remove [DataType(DataType.Date)] from your model, the input field in Chrome is rendered as type="datetime" and won't show the datepicker either.

AlexB
  • 7,302
  • 12
  • 56
  • 74
bernieb
  • 109
  • 3
  • Thanks Bernie. I wasn't so trouble with the picker showing up as I was with the data not being put into the input box. This is good to know though. – Ben Finkel Oct 04 '12 at 14:38
  • Opera renders a datepicker though. Use modernizr to do some polyfill – cleftheris Oct 10 '12 at 14:39
  • 1
    If it's supposed to be a date, it should be rendered as an input of type `date`. Using `datetime` as a work-around is inappropriate, since it doesn't semantically represent the data. – Chris Pratt Jun 26 '14 at 15:26
4

I still had an issue with it passing the format yyyy-MM-dd, but I got around it by changing the Date.cshtml:

@model DateTime?

@{
    string date = string.Empty;
    if (Model != null)
    {
        date = string.Format("{0}-{1}-{2}", Model.Value.Year, Model.Value.Month, Model.Value.Day);
    }

    @Html.TextBox(string.Empty, date, new { @class = "datefield", type = "date"  })
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
markpcasey
  • 559
  • 1
  • 10
  • 18
  • thank you finally this worked, i tried `string.Format("{0}/{1}/{2}")` to get `dd/mm/yyyy` format, and it works fine, i used database first method but DisplayFormat didn't worked with partial class, don't know why?, anyway anyone if needed try [this](http://forums.asp.net/t/1670255.aspx?EditorFor+DateTime+field+how+to+add+format) method , i didn't try but if anyone needed , hope it helps – Shaiju T Mar 30 '15 at 15:36
3

Reply to MVC4 DataType.Date EditorFor won't display date value in Chrome, fine in IE

In the Model you need to have following type of declaration:

[DataType(DataType.Date)]
public DateTime? DateXYZ { get; set; }

OR

[DataType(DataType.Date)]
public Nullable<System.DateTime> DateXYZ { get; set; }

You don't need to use following attribute:

[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]

At the Date.cshtml use this template:

@model Nullable<DateTime>
@using System.Globalization;

@{
    DateTime dt = DateTime.Now;
    if (Model != null)
    {
        dt = (System.DateTime)Model;

    }

    if (Request.Browser.Type.ToUpper().Contains("IE") || Request.Browser.Type.Contains("InternetExplorer"))
    {
        @Html.TextBox("", String.Format("{0:d}", dt.ToShortDateString()), new { @class = "datefield", type = "date" })
    }
    else
    {
        //Tested in chrome
        DateTimeFormatInfo dtfi = CultureInfo.CreateSpecificCulture("en-US").DateTimeFormat;
        dtfi.DateSeparator = "-";
        dtfi.ShortDatePattern = @"yyyy/MM/dd"; 
        @Html.TextBox("", String.Format("{0:d}", dt.ToString("d", dtfi)), new { @class = "datefield", type = "date" })
    } 
}

Have fun! Regards, Blerton

  • If you do it this way, Chrome won't give you a date picker. I'm using your solution, but modifying so that 1) I DO use the `DisplayFormat` attribute 2) Change the test to check if the browser type is chrome, then do `@Html.EditorFor(m=>m.EstPurchaseDate)` 3) Else do `@Html.TextBox("EstPurchaseDate", dt.ToString("MM/dd/yyyy"))` Note: on #2, a better check would be if the browser understands HTML5, but I don't know how to do that. – David May 06 '14 at 21:28
  • 4
    Downvoting for browser detection in server side code. – Tetsujin no Oni Nov 06 '14 at 18:54
2

If you need to have control over the format of the date (in other words not just the yyyy-mm-dd format is acceptable), another solution could be adding a helper property that is of type string and add a date validator to that property, and bind to this property on UI.

    [Display(Name = "Due date")]
    [Required]
    [AllowHtml]
    [DateValidation]
    public string DueDateString { get; set; }

    public DateTime? DueDate 
    {
        get
        {
            return string.IsNullOrEmpty(DueDateString) ? (DateTime?)null : DateTime.Parse(DueDateString);
        }
        set
        {
            DueDateString = value == null ? null : value.Value.ToString("d");
        }
    }

And here is a date validator:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public class DateValidationAttribute : ValidationAttribute
{
    public DateValidationAttribute()
    {
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (value != null)
        {
            DateTime date;

            if (value is string)
            {
                if (!DateTime.TryParse((string)value, out date))
                {
                    return new ValidationResult(validationContext.DisplayName + " must be a valid date.");
                }
            }
            else
                date = (DateTime)value;

            if (date < new DateTime(1900, 1, 1) || date > new DateTime(3000, 12, 31))
            {
                return new ValidationResult(validationContext.DisplayName + " must be a valid date.");
            }
        }
        return null;
    }
}
Martin Staufcik
  • 8,295
  • 4
  • 44
  • 63