MVC , JsonResult , DateTime and TimeZone
The jsonresult of date time is serializing to the string /Date and some integer value starting with 1970 . The problem is that the browser interprets this value accordingly to the LOCAL TimeZone – and thus the same date is going to be interpreted with a difference.
I was thinking that I can adjust from UTC time offset of the server( obtained with .NET from TimeZoneInfo.Local.BaseUtcOffset.TotalMinutes) and the UTC time offset of the client( obtained with (new Date()).getTimezoneOffset() + UTCServerMinutes; ). Unfortunately, the code does not work for SAMOA ( 13 hours difference).
Pay attention that the server is sending SAME data – just the browser is interpreting from the local user time zone.
So the solution is to convert the date to a string ( I have chosed yyyy-MM-ddTHH:mm:ss) and interpret in javascript( see date2 below).
The server code – I have put my birthdate 16 april 1970
DateTime res = new DateTime(1970, 04, 16, 22, 0, 0); [HttpPost] public JsonResult GetDateBirth() { var str = res.ToString("s"); return Json(new { date =res, datestring=str, ok = true }); }
The Javascript code:
function GetJsonDate() { $.ajax({ type: "POST", url: '@Url.Action("GetDateBirth")', datatype: "JSON", contentType: "application/json; charset=utf-8", success: function (returndata) { if (returndata.ok) { window.alert('The server is sending:' + returndata.date + " -- " + returndata.datestring); var d = parseInt(returndata.date.substr(6)); var date1 = new Date(d); var date2 = dateFromSortable(returndata.datestring); var date3= getDateString(returndata.date); window.alert('original: ' + date1 + '\r\n' + ' iso correct:'+ date2 + '\r\n'+ ' utc difference not good:' + date3); } else { //this is an error from the server window.alert(' error : ' + returndata.message); } } } ); } function dateFromSortable(dateStr) { var parts = dateStr.match(/\d+/g); return new Date(parts[0], parts[1] - 1, parts[2], parts[3], parts[4], parts[5]); } function getDateString(jsonDate) { //does not work correctly for SAMOA - it have some hours difference var UTCServerMinutes = @serverMinutes; if (jsonDate == undefined) { return ""; } var utcTime = parseInt(jsonDate.substr(6)); var dateUtc = new Date(utcTime); var minutesOffset = (new Date()).getTimezoneOffset() + UTCServerMinutes; var milliseconds = minutesOffset * 60000; var d = new Date(dateUtc.getTime() + milliseconds) return d; }
How to test it:
Run the project. Click “Get Json Date” – and you will see the three dates equal.
Now change the time zone to Samoa ( or other, if you live in Samoa )
Click again on “Get Json Date” – the date will same 16 april 1970 just for the date2 – obtained from dateFromSortable javascript function.
Please note that the local time zone is NOT affecting the values transmitted via ViewBag/ViewData/Model, but just the ones transmitted via Json.
The project can be downloaded from here
Si-au dat si la Microsoft seama de problemele astea, si in ASP.NET WebAPI au trecut la ISO8601 format pentru date in JSON, care nu mai variaza in functie de timezone: http://www.hanselman.com/blog/OnTheNightmareThatIsJSONDatesPlusJSONNETAndASPNETWebAPI.aspx
Yes, but it dows not still work in plain old MVC ( even4) with JsonResult.
We get rid of this by creating a custom JsonResult where the date formating is taken in charge by Newtonsoft.Json to wich ew create a csuton DateTime conversion ! Way cleaner !
Did you test throughfully Newtonsoft.Json package? I am sure that is good – but I do not want to introduce more unknown differences between MVC default Json serializer and Newtonsoft Json serializer
As you probably know, Newtonsoft.Json has been choosen also by Microsoft as the default JSON serializer in WebAPI, and is the most used library for this today..
If you set properly the DateTimeKind of each datetime both the Microsoft serializer and the json serializer works in the same way. They behave differently just when the DateTimeKind is set to Unspecified that is when we dont declare clearly if the DateTime is in local or universal time. In such ambigous situation one serializer assume local time and the other universal time so they behave differentky. Moreover the browser doesnt interpret the datetime in local time it interprets it in utc time…but shows up it in local time of the browser…and this create the xonfusion
Hello Francesco
Please show code.
suppose you have a datetime x expressed in local time. Before serializing it with ANY serializer one must be sure the fact it expresses a local time is explicitely declared by setting x.Kind =DateTimeKind.Local. After that ALL serializer will do the same thing, that is, converting it il Utc time before serializing it. This means the client will receive an Utc time. However, when it is written in the javascript consolle it is shown in the browser local time with the indication of the local time zone. This is normally acceptable. In fact if the server and client are in the same timezone the user will see exactly the same time we had on the server. If the user is in a different timezone the time will be automatically shown converted in the user timezone. Thiw behaviour is normally acceptable, However, it is not acceptable when other dates are not sent in json format but rendered directly on the server side say in a textbox. In this case there is an incongruence because the two dates would show in different timezones. In this case the only way is to send also the json date as a string to the clkent as you suggested. In any case it is simply false that the Microsoft serialize doesnt work properly while the newsoft serialize works properly. The only difference between them is that each of them assume a different Kind when no Kind is explicitely declared
Yes, I know about Newtonsoft serializer. Just do not want to add another framework to existing one.
The point I was trying to point out is exactly that the Newtonsoft serializer adds NOTHING new respect to Microsoft serializer for what concern Timezone problems. It makes just different assumptions when the Kind is set to Unspecified, so it appears to have a different behavior but this “different behavior” just comes from the error of not setting the Kind of a DateTime before sending it to the client. When the developer set the kind of a DateTime the two serializer behave exactly in the same way.
I published on github https://github.com/xunter/dateup js util to auto convert date strings to the Date object. And also, it auto-integrates with jQuery.ajax. So, after ajax.post/get you will receive js object with Date fields.
It converts string in ISO8601 format to the Date object.
It is not a wide library but just my expirience and seems to work.
Thank you
real thankful free to get this page
var d = parseInt(returndata.date.substr(6));
A little hacky huh? Only because the default json serializer uses that awful formatting for dates ‘/Datexxxxxxxx/’.
Scott Hanselman has a post on his block about json and dates and recommends to use the newtonsoft json serializer to convert dates to ISO format instead. Many will tell you to do the same, it is much cleaner and Microsoft includes the newtonsoft.json serializer as the default one on Web Api.
I use it to replace the default Json.Encode output when I need the controller dumping json data on the view manually. It also handles circular references, which should be reason enough to use it instead already.
Yes, I know that JSonSerializer is default in WebAPI.However, it did not include as default in MVC4. Must be some incompatibilities then, right?
Obviously they will never switch to another JSON serializer in MVC4 (and future versions) because that would be a breaking change for existing applications, and they must preserve the backwards compatibility.
On the other hand, the developer has the option to change the JSON serializer/parser or to use ASP.NET WebAPI for proper REST endpoints that return JSON.
question :
when displaying “time” say in a label – why not use “code behind” ex (this is in C#)
=======
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
this.lblCurrentDate.Text = DateTime.Now.ToString(“d”);
I said already: the problem is affecting Ajax requests – not usual code