How to make ASP.Net MVC model binder treat incoming date as UTC?

This problem persists in ASP.NET Core 2.0. The following code will resolve it, supporting ISO 8601 basic and extended formats, properly preserving the value and setting DateTimeKind correctly. This aligns with the default behavior of JSON.Net’s parsing, so it keeps your model binding behavior aligned with the rest of the system.

First, add the following model binder:

public class DateTimeModelBinder : IModelBinder
{
    private static readonly string[] DateTimeFormats = { "yyyyMMdd'T'HHmmss.FFFFFFFK", "yyyy-MM-dd'T'HH:mm:ss.FFFFFFFK" };

    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
            throw new ArgumentNullException(nameof(bindingContext));

        var stringValue = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).FirstValue;

        if (bindingContext.ModelType == typeof(DateTime?) && string.IsNullOrEmpty(stringValue))
        {
            bindingContext.Result = ModelBindingResult.Success(null);
            return Task.CompletedTask;
        }

        bindingContext.Result = DateTime.TryParseExact(stringValue, DateTimeFormats,
            CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var result)
            ? ModelBindingResult.Success(result)
            : ModelBindingResult.Failed();

        return Task.CompletedTask;
    }
}

Then add the following model binder provider:

public class DateTimeModelBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        if (context == null)
            throw new ArgumentNullException(nameof(context));

        if (context.Metadata.ModelType != typeof(DateTime) &&
            context.Metadata.ModelType != typeof(DateTime?))
            return null;

        return new BinderTypeModelBinder(typeof(DateTimeModelBinder));
    }
}

Then register the provider in your Startup.cs file:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options =>
    {
        ...

        options.ModelBinderProviders.Insert(0, new DateTimeModelBinderProvider());

        ...
    }
}

Leave a Comment