4

I'm having an issue that I cannot figure out.

I try to deal ALWAYS with UTC DateTime at server side.

I have an AspNetCore Mvc application with an endpoint that accepts queries that may include DateTimes. I want Mvc to understand that these dates are already in UTC and not to transform them "again".

My system is in Spain, (UTC +2)

If I send an http request to my localhost server like this:

http://localhost:50004/api/Resources?appliesOn=2018-06-30T18:00:00.000Z

I want to have the deserialized datetime as UTC representing the same date as:

DateTime.SpecifyKind(new DateTime(2018, 6, 30, 18, 0, 0), DateTimeKind.Utc)

But I can see that Mvc always transforms the date 2018-06-30T18:00:00.000Z into two hours later: 2018-06-30 20:00:00

I have tried to tell Mvc to use UTC json serializer/deserializer but nothing changes:

services
  .AddMvc()
  .AddJsonOptions(options =>
  {
      options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
  });

Is there a way to send query parameters in an http GET request already as a representation of UTC datetime? I understood a Date in ISO 8601, if it has a suffix Z it means "zero-offset" which should be interpreted already as UTC date time. Why Mvc is then transforming this and adding 2 hours offset?

Any clarification would be much appreciated!

PS: This is my endpoint, nothing special as you can see:

[HttpGet("")]
public IActionResult GetResources()
{
    var displayUri = Request.GetDisplayUrl();
    var requestUri = new Uri(displayUri);
    var filter = _filteredRequestFactory.Create(requestUri);
    var resources = _myProjection.GetResourcers(filter);
    return Ok(resources);
}

2 Answers 2

6

This issue is still there even with ASP.NET-Core 3.1 when using UTC date-times in query. For instance with [FromQuery].

In this github-issue is a also a very well working model-binder provided.

Basically you can copy & pase it and just register it

For Web-API controllers only:

services.AddController(options => options.ModelBinderProviders.Insert(0, new DateTimeModelBinderProvider());

For full-fledged MVC pipeline

services.AddMvc(options => options.ModelBinderProviders.Insert(0, new DateTimeModelBinderProvider());
Sign up to request clarification or add additional context in comments.

Comments

4

Thanks to another question in StackOverflow I found out that the reason this happens is because AspNetCore Mvc deserializer does not even use Json.Net deserializer in a GET http request to deserialize the query parameters.

Therefore, the following request: http://localhost:50004/api/DateTests?date=2018-06-15T18:00:00.000Z

would be captured by my endpoint:

[HttpGet("")]
public IActionResult GetDate(DateTime date)
{
    return Ok(date.ToString("o"));
}

and return the date in ISO 8601 format as follows: 2018-06-15T20:00:00.0000000+02:00

It deserializes the query parameter as if it was a local time date, and it applies the UTC + 2 (because the app is in Spain).

I needed a way to tell AspNet Core Mvc deserializer to understand that the query parameter that looks like a date, should be treated already as an UTC date and not modified it when deserializing.

The answer was to create a custom model binder and apply it either to that endpoint or globally.

I found a good implementation and after adding that model binder provider and model binder,

my endpoint now returns for the request with ?date=2018-06-15T18:00:00.000Z :

2018-06-15T18:00:00.0000000 as a DateTime of UTC kind.

If I pass a ?date=2018-06-11T18:00:00+0100 it will be retrieved as a local time kind and the result would be: 2018-06-11T19:00:00.0000000+02:00

as desired

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.