Assume we have action:
[HttpGet]
public Task<IActionResult> Foo(DateTime date)
{
var utc = date.ToUniversalTime();
}
It seems like MVC framework by default convert UTC DateTime to Local (somewhere in middleware). How can I turn off this behaviour and get rid of additional transformations?
UPD:
Chrome dev. console (network tab) shows me such query parameter:
date:2017-12-01T00:00:00.000Z
but in controller I see:
{01/12/2017 03:00:00}
string dateTime = Request. QueryString["DateStarted"]; DateTime dt = Convert. ToDateTime(dateTime); Response.
UTC, or Universal Time Coordinated, is the most precise and commonly referred to time standard. Since the 1970s, this time standard has been globally used as the most precise time standard, instead of formerly used GMT standard, which has turned now into a regular time zone.
Times are expressed in UTC (Coordinated Universal Time), with a special UTC designator ("Z"). Times are expressed in local time, together with a time zone offset in hours and minutes. A time zone offset of "+hh:mm" indicates that the date/time uses a local time zone which is "hh" hours and "mm" minutes ahead of UTC.
DateTime
should not be used when accurate timezone-based times are necessary. That's why DateTimeOffset
exists. By default, DateTime.Kind
is DateTimeKind.Unspecified
. In other words, it's up to you, after post, to determine what it should be interpreted as. The problem is that you can really only assume DateTimeKind.Utc
, as that's the only thing you can interpret as a DateTime
correctly. Posting the user's local time leaves you stranded, because DateTimeKind.Local
actually means the server's local time, which usually will not the be same as the client's.
However, even in HTML5, posting a full datetime with timezone is virtually impossible. Although input types such as datetime
and datetime-local
exist, they are not implemented in any major browser. If you want to post dates with times and timezone, then you'll actually need three properties on your view model:
public DateTime Date { get; set; }
public TimeSpan Time { get; set; }
public string TimeZone { get; set; }
The TimeZone
property assumes you'll use a dropdown list composed of values from TimeZoneInfo.GetSystemTimeZones()
. If you want to use a different setup, you'll need some way to map to/from those values, since that's all you have to work with in C# to get an offset. However, you could simply allow the user to post an offset, instead, but that's less user-friendly, and may be difficult for some users. In particular, they would need to understand not only what the concept "offset from UTC" means, but also that take into account the current status of daylight savings time and adjust that offset according to the actual date.
Regardless, each of these properties can easily be mapped to a input type: date
/time
and a select
/time
in the case of the TimeZone
, depending on whether you go with a dropdown or an manual offset entry. They are also all easily mapped back onto your view model by the modelbinder following a post. You then just need to create a DateTimeOffset
from that information, which is what you'd actually persist on your entity class.
var offset = TimeZoneInfo
.FindTimeZoneById(model.TimeZone)
.GetUtcOffset(model.Date)
var dateTimeOffset = new DateTimeOffset(model.Date.Add(model.Time), offset);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With