Simon Miller Team : Web Development Tags : Web Development MVC

Parsing Australian format DateTimes in MVC model binding

Simon Miller Team : Web Development Tags : Web Development MVC

I don't know why, but .NET defaults to US format dates for everything. It would have made sense if Microsoft chose to go with SQL date format i.e. yyyy-MM-dd, but they didn't. You can set all the globalisation settings in the world in your web.config but it won't help you when it comes to model binding. That stuff is hard wired to accept US date formats and SQL date formats only.

So how do you get around it? A custom model binder!

This seems a bit over the top, as it is my opinion that the globalisation settings - or perhaps a second setting for model binding formats - should be a simple configuration in your web.config. Alas...

After a lot of head scratching I found this fantastic post that shed light on a solution. The following code will happily parse en-AU format date(times) from your forms into MVC models, when set by a jQuery date picker.

public class CustomDateBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            if (controllerContext == null)
                throw new ArgumentNullException("controllerContext", "controllerContext is null.");
            if (bindingContext == null)
                throw new ArgumentNullException("bindingContext", "bindingContext is null.");
            var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
            if (value == null)
                throw new ArgumentNullException(bindingContext.ModelName);
            CultureInfo cultureInf = (CultureInfo)CultureInfo.CurrentCulture.Clone();
            cultureInf.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy";
            bindingContext.ModelState.SetModelValue(bindingContext.ModelName, value);
            try
            {
                var date = value.ConvertTo(typeof(DateTime), cultureInf);
                return date;
            }
            catch (Exception ex)
            {
                bindingContext.ModelState.AddModelError(bindingContext.ModelName, ex);
                return null;
            }
        }
    }

You then need to reference it from your Application_Start() or OnApplicationStarted() method which may be in your global.asax or in case of Umbraco in your UmbracoStartup class.

ModelBinders.Binders.Add(typeof(DateTime), new CustomDateBinder());
ModelBinders.Binders.Add(typeof(DateTime?), new CustomDateBinder());

Simple and elegant. Sure it still appears to be US date format when you debug, but I can live with that.