Click here to Skip to main content
15,887,485 members
Articles / Web Development / HTML
Tip/Trick

DateTime Issue In MVC

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
28 Feb 2016CPOL4 min read 74.4K   775   9   4
When you are dealing with Date&Time input from user, it's always complicated to handle the Date&Time format. You are not sure about how you will handle the user input format. So, here is the solution.

Introduction

This is a simple tip to let you handle the data and time scenarios working in MVC. Suppose you have a scenario in which you take date input from user. Let's say Date of Birth. Now let's say user enters 10.-11-1995, Now how will you or the code determine which is day and which is month in the input. So it can be a serious problem that must be handled with care.

The root of the problem is .NET framework will always assume that the incoming date is according to the current culture. But when you are building multi-culture website, the problem becomes bigger. Let's see how we can standardize such things in MVC.

Background

There is not much background or pre-requisites to start with this tip. This includes a very basic knowledge of MVC. I expect that you are aware of how you bind data from controller to the views using Models. In case you are very new to MVC, you can take a look at the following article first:

Secondly, I hope you are familiar with Inheritance concept of OOPS. You can override the default behaviours of Interface/Class methods by inheritance. This is all about the background. Now, let's start.

Using the Code

To have a better understanding, you can follow the steps resulting in an application with Independent DateFormat architecture.

  1. First of all, create an MVC Empty application.
  2. Create a Model Names Employee with property as follows:
    C#
    public class Employee
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        [DataType(DataType.Date), DisplayFormat(DataFormatString = @"{0:dd\/MM\/yyyy HH:mm}",
                ApplyFormatInEditMode = true)]
        public DateTime DOB { get; set; }
        [DataType(DataType.Date), DisplayFormat(DataFormatString = @"{0:dd\/MM\/yyyy HH:mm}",
                ApplyFormatInEditMode = true)]
        public DateTime JoiningDate { get; set; }
    }
    
  3. Create a Home Controller and create a view for Index method. The index view we will use to add the new Employee record. Hence, make the view of type 'Employee'. Following is the HTML code for my Index.cshtm page.
    HTML
    @{
        Layout = null;
    }
    @model MVCDateTimeDemo.Models.Employee
    <!DOCTYPE HTML>
    <html>
      <head>
        <link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.2/css/bootstrap-combined.min.css" 
        rel="stylesheet">
        <link rel="stylesheet" type="text/css" media="screen"
         href="http://tarruda.github.com/bootstrap-datetimepicker/assets/css/bootstrap-datetimepicker.min.css">
      </head>
      <body>
      @using (Html.BeginForm("SaveEmployee", "Home", FormMethod.Post, 
      new { enctype = "multipart/form-data", id = "form1" }))
      {
        <div>
        <table>
             @*@foreach (var employee in Model.Employees)
             { 
                    <tr><td>@employee.FirstName</td><td>@employee.LastName</td>
                    <td>@employee.DOB.ToString("dd/MM/yyyy")</td>
                    <td>@employee.JoiningDate.ToString("dd/MM/yyyy")</td></tr>
             }*@
            </table>
            <br />
            @Html.HiddenFor(m => m.Id)
            <br />
            @Html.TextBoxFor(m => m.FirstName, new { placeholder = "First name" })
            <br />
            @Html.TextBoxFor(m => m.LastName, new { placeholder = "Last Name" })
            <br />
            
            <div id="datetimepicker1" class="input-append date">
          @Html.TextBoxFor(m => m.DOB, "{0:dd/MM/yyyy HH:mm}", 
          new { placeholder = "Date Of Birth", @class = "dtPicket" })
          <span class="add-on"><i data-time-icon="icon-time" 
          data-date-icon="icon-calendar"></i>
          </span>
        </div>
            <br />
             <div id="datetimepicker2" class="input-append date">
          @Html.TextBoxFor(m => m.JoiningDate, "{0:dd/MM/yyyy HH:mm}", 
          new { placeholder = "Joining Date", @class = "dtPicket" })
          <span class="add-on"><i data-time-icon="icon-time" 
          data-date-icon="icon-calendar"></i>
          </span>
        </div>
            <br />
            <input type="submit" value="Submit" />
        </div>
        <script type="text/javascript"
         src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js">
        </script> 
        <script type="text/javascript"
         src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.2/js/bootstrap.min.js">
        </script>
        <script type="text/javascript"
         src="http://tarruda.github.com/bootstrap-datetimepicker/assets/js/bootstrap-datetimepicker.min.js">
        </script>
        <script type="text/javascript"
         src="http://tarruda.github.com/bootstrap-datetimepicker/assets/js/bootstrap-datetimepicker.pt-BR.js">
        </script>
        <script type="text/javascript">
            $('#datetimepicker1, #datetimepicker2').datetimepicker({
                format: 'dd/MM/yyyy HH:mm'
            });
        </script>
      }
      </body>
    <html>
  4. Now add an action to the Home controller that will handle the post request of the above page. As you can see, I have added 'SaveEmployee' action to Form attribute.
  5. Create a view to display the records.
  6. You can use database or can create a method that returns List of employees temporarily binding the data.

Now, we are ready with application to Save and display the Employees. Just build and run the project

Problem

Enter the date informat dd/MM/yyyy, let's say 25/10/1990 00:00:00. You expect the same value at controller level. But when you debug the code, you will see "01/01/001 00:00:00".

Why So?: This is because the .NET Framework will consider that the input value is the same culture the machine has on which your code is hosted until you explicitly mention the culture in your web.config file. But what if you have multiple languages in you webiste. Then, every language has its own culture and every culture has a different (almost) date frmat. Hence, the problem bounced back at high risk this time.

But you have specified the DataAnnotation DisplayFormat attribute:

You will be thinking here that you are getting this issue despite mentioning the display format in Model data annotation attributes. Why is it not applied ??

Solution: The data annotation is actually applied but what actually annotation does is to validate the data before saving. Now as per user, 25/10/1990 is a valid date but not for .NET MVC Compiler. Now to force compiler to pass the input as per your specified format is to override the default Model Binder. So to do that, please see the following steps carefully:

Step 1

Code for overriding the DefaultModelBinder.

Following is the code that needs to be added to Global file.

Global File

As you can see above, in the Application_Start method of Global file, I have added an additional line than your Global file has:

JavaScript
ModelBinders.Binders.Add(typeof(DateTime), new CustomDateModelBinder());

This line says, you are overriding the default model finder for model property of type DateTime.

Step 2

Now let's write the code for our CustomeDataModelBinder.

C#
public class CustomDateModelBinder : DefaultModelBinder
{
    public override object BindModel
    (ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var displayFormat = bindingContext.ModelMetadata.DisplayFormatString;
        var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

        if (!string.IsNullOrEmpty(displayFormat) && value != null)
        {
            DateTime date;
            displayFormat = displayFormat.Replace
            ("{0:", string.Empty).Replace("}", string.Empty);
            if (DateTime.TryParseExact(value.AttemptedValue, displayFormat,
            CultureInfo.InvariantCulture, DateTimeStyles.None, out date))
            {
                return date;
            }
            else
            {
                bindingContext.ModelState.AddModelError(
                    bindingContext.ModelName,
                    string.Format("{0} is an invalid date format", value.AttemptedValue)
                );
            }
        }

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

Make sure this code should be written to Global file only as DefaultModelBinder context is within Global file.

Now let's have an overview of our file system so that we can have clear view of what files I have added.

Image 2

Step 3

Build and run the code.

Now try to run your code and you will see that the Date format is working in the right way you wanted.

Points of Interest

  1. Custom Model Binder overrides the default behaviour of MVC Model Binder by overriding the system culture.
  2. Display custom message for validation error for model property.
  3. Here, I have added the customModelBinder for Model property of type DateTime only. In case you want to do the same for Decimal/Int, etc., just add the entry for respective Application_Start action and you are done. No need to re-write Custom Override method.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
India India
Puneet Goel is an IT Professional with 8+ years. He is specialized in Microsoft Technologies (Asp.NET, SQL Server, Ajax, Jquery, JavaScript, MVC, and Angular). He is an avid member of several development communities and a serial blogger.He loves to learn new technology, do experiments with existing ones, and always happy to help the community.

Comments and Discussions

 
QuestionUpload the code in zip format Pin
Tridip Bhattacharjee2-Mar-16 0:22
professionalTridip Bhattacharjee2-Mar-16 0:22 
AnswerRe: Upload the code in zip format Pin
Er. Puneet Goel2-Mar-16 0:58
professionalEr. Puneet Goel2-Mar-16 0:58 
QuestionWhy change date display? Pin
lespauled29-Feb-16 6:45
lespauled29-Feb-16 6:45 
AnswerRe: Why change date display? Pin
Er. Puneet Goel29-Feb-16 18:29
professionalEr. Puneet Goel29-Feb-16 18:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.