8

I'm sending dates from my web app in UTC format, but when I recieve them on the server side, the JSon serializer (which is probably used by setting up your model) makes this in a local date & time with DateTimeKind.Local relative to the server's time zone.

When I do a DateTime.ToUniversalTime() I'm getting the proper UTC date, so this isn't a problem. Conversion works correctly and dates are sent the way they should... but.... I don't like to make a call to 'ToUniversalTime()' on every date on my model before I store it into a database... This is prone to errors and easy to forget when you have a big app.

So here's the question: Is there a way to tell MVC that incoming dates should always be expressed in UTC format?

7
  • Seems like the deserializer is doing its job well, if the values in the DateTime object are correct. Dates might get unwieldy if you start to treat some as special on the server. Commented Mar 2, 2012 at 20:55
  • 1
    @dtryon: No, I think preserving them as UTC makes a lot more sense. Local times can very easily be ambiguous - so the deserializer may well be losing information here, which is surely a cardinal sin. Commented Mar 2, 2012 at 20:57
  • @JonSkeet but as long as ToUniversalTime() is returning correct UTC, isn't it being expressed correctly? Commented Mar 2, 2012 at 21:14
  • So I guess you want some way to inject the AssumeUniversal DatetimeStyles flag into the parse. Commented Mar 2, 2012 at 21:17
  • 1
    @dtryon: It's worked so far, but unless the OP is in a time zone which doesn't observe daylight saving time, it won't work at all times. Around autumnal daylight saving transitions, you can end up with two UTC values which map to the same local time (as the clock goes back). If the deserializer converts two different "source" values to the same "target" value, that's lost information by definition. Commented Mar 2, 2012 at 21:17

1 Answer 1

3

After digging a bit more, I've found a way to make this work.

The problem wasn't so much the serializer, only the problem that the model's dates aren't expressed in UTC but in local time. ASP.Net allows you to create custom model binders and I think this is the key to change dates to UTC once they are deserialized.

I've used the following code to make this work, there might be a few bugs to iron out, but you will get the idea:

public class UtcModelBinder : DefaultModelBinder
{
  protected override void SetProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor, object value)
  {
    HttpRequestBase request = controllerContext.HttpContext.Request;

    // Detect if this is a JSON request
    if (request.IsAjaxRequest() &&
      request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
    {
      // See if the value is a DateTime
      if (value is DateTime)
      {
        // This is double casting, but since it's a value type there's not much other things we can do
        DateTime dateValue = (DateTime)value;

        if (dateValue.Kind == DateTimeKind.Local)
        {
          // Change it
          DateTime utcDate = dateValue.ToUniversalTime();
          if (!propertyDescriptor.IsReadOnly && propertyDescriptor.PropertyType == typeof(DateTime))
            propertyDescriptor.SetValue(bindingContext.Model, utcDate);

          return;
        }
      }
    }

    // Fall back to the default behavior
    base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value);

  }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.