I am building a MVC 3 application where the users may not be in the same time zone, so my intent was to store everything in UTC and convert from UTC to local time in the views and localtime to UTC on submissions.
Doing some browsing though there doesn't seem to be a lot of good solutions to this. To be honest, I sort of expected an attribute to be available to auto convert UTC time into local time at least, but it seems not to exist.
I feel like just trying to be diligent about manually converting every input to UTC and manually converting every view to local time display will be very error prone and lead to difficult to detect bugs where the time is not converted to or from.
Any suggestions on how to deal with this as a general strategy?
EDIT Everyone seems very stuck on the "how do I get the client timezone" piece, which as I mention in one of the comments is not my concern. I am fine with a user setting that determines their timezone, so assume I already know what the client time zone is...that doesn't address my problem.
Right now, on each view when I render a date, I would need to call a method to render it in the local time zone from utc. Every time I send a date for submission to the server I need to convert it from the local timezone to UTC. If I forget to do this there will be problems...either a submitted date will be wrong or client side reports and filters will be wrong.
What I was hoping existed was a more automated method, especially since the view model is strongly typed in MVC 3 I was hoping for sum magic to be able to at least automatically render in a time zone, if not handle the submission, just like the date format or range can be controlled by an attribute.
So like
[DateRange] Public DateTime MyDate
I could have something like
[ConvertToUTC(offset)] Public DateTime MyDate
Anyway, I guess it look like my only approach would be to write a custom data annotation to render it in a time zone, and a override on the MVC 3 model binder so incoming dates are converted unless I want to wrap ever date in a method call. So unless anyone has further comments or suggestions it will be one of those two options, I'm just surprised something doesn't exist already to do this.
If I do implement a solution I will be sure to post it.
Edit 2 Something like This http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.aspx for MVC 3 views and view models is what I am looking for.
Final Edit I marked epignosisx answer as correct, but also have a few comments to add. I found something similar here: http://dalldorf.com/blog/2011/06/mvc3-timezones-1/ With an implementation of getting the timezone from the client by placing it in the cookie for people that want that in part 2 (link below since the link on the first part of the article to part 2 doesn't work) http://dalldorf.com/blog/2011/09/mvc3-timezones-2/
Its important to note with these approaches that you MUST you Editfor and Displayfor instead of things like TextForFor as only EditFor and DisplayFor make use of the metadata providers used to tell MVC how to display the property of that type on the model. If you access the model values directly in the view (@Model.MyDate) no conversion will take place.
A time zone is a region of the Earth that has adopted the same standard time, usually referred to as the local time. Most adjacent time zones are exactly one hour apart, and by convention compute their local time as an offset from Greenwich Mean Time (see also UTC).
Setting the same time zone to a partner makes it easier to conduct trading since business hours match. Different time zones force businesses to factor in time zone conversion when dealing with international business and can negatively impact worker productivity.
A time zone is an area which observes a uniform standard time for legal, commercial and social purposes. Time zones tend to follow the boundaries between countries and their subdivisions instead of strictly following longitude, because it is convenient for areas in frequent communication to keep the same time.
You could handle the problem of converting UTC to user local time by using website-wide DisplayTemplate for DateTime.
From your Views you would use @Html.DisplayFor(n => n.MyDateTimeProperty)
The second problem is tougher to tackle. To convert from user local time to UTC you could override the DefaultModelBinder. Specifically the method SetProperty. Here is a naive implementation that demonstrates the point. It only applies for DateTime but could easily be extended to DateTime?. Then set it up as your Default binder in the Global.asax
public class MyDefaultModelBinder : DefaultModelBinder { protected override void SetProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor, object value) { //special case for DateTime if(propertyDescriptor.PropertyType == typeof(DateTime)) { if (propertyDescriptor.IsReadOnly) { return; } try { if(value != null) { DateTime dt = (DateTime)value; propertyDescriptor.SetValue(bindingContext.Model, dt.ToUniversalTime()); } } catch (Exception ex) { string modelStateKey = CreateSubPropertyName(bindingContext.ModelName, propertyDescriptor.Name); bindingContext.ModelState.AddModelError(modelStateKey, ex); } } else { //handles all other types base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value); } } }
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