Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSON Date Serialization and Time Zones

I'm having issues displaying the correct date on the client's browser using a JSON serialized object. The user is able to define what time zone they want to view data as. Given this, I convert the UTC date to the user's time zone on the server. Then I want to serialize the date/times (which are already converted to their defined time zone) to the browser via JSON.

Seems simple, however the JSON serializers I've been using have been severely mucking up my dates. The server is in UTC and the client is in Central (-6). The dates are being ajusted (-12 hours) even though I am specifying the DateTime.Kind to Unspecified.

Somehow .NET knows what time zone the client's browser is at and what time zone the server is in and it is negating -6 from my dates/times even though I've already ajusted the time per the user's global settings and set the dates' kind to be unspecified. How can I get the JSON serializers to NOT try and adjust my dates?

List<ErrorGridModel> models = Mapper.Map<ErrorCollection, List<ErrorGridModel>>(errors);
foreach (ErrorGridModel m in models)
{
    //convert UTC dates to user local dateTime - split out date vs. time for grouping & splitting columns
    DateTime dtLocal = TimeZoneInfo.ConvertTimeFromUtc(m.ErrorDate, this.AppContext.User.TimeZoneInfo);
    m.ErrorDate = new DateTime(dtLocal.Year, dtLocal.Month, dtLocal.Day, 0, 0, 0, DateTimeKind.Unspecified);
    m.ErrorTime = new DateTime(1900, 1, 1, dtLocal.Hour, dtLocal.Minute, dtLocal.Second, DateTimeKind.Unspecified);
}
IQueryable<ErrorGridModel> dataSource = models.AsQueryable();
return new ContentResult() { Content = JsonConvert.SerializeObject(dataSource.ToDataSourceResult(request), new JsonSerializerSettings() { DateFormatHandling = DateFormatHandling.MicrosoftDateFormat }), ContentType = "application/json" };
//return Json(dataSource.ToDataSourceResult(request));

ISO dates appear to work, but I can't use them as I have 3rd party controls that want the older Microsoft format... which adjusts the time zones on me.

like image 760
Bill Christenson Avatar asked Jan 20 '13 18:01

Bill Christenson


1 Answers

When you're trying to control offsets, don't rely on DateTimeKind.Unspecified. It has a few quirks that are often interpreted as Unspecified == Local. The only way to get Json.Net to specifically encode the correct offset (regardless of ISO or MS format) is to pass it a DateTimeOffset instead of a DateTime.

// Start with the UTC time, for example your m.ErrorDate.
// Here I demonstrate with UtcNow.  Any DateTime with .Kind = UTC is ok.
var dt = DateTime.UtcNow;

// Use the appropriate time zone, here I demonstrate with EST.
var tzi = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");

// Get the offset from UTC for the time zone and date in question.
var offset = tzi.GetUtcOffset(dt);

// Get a DateTimeOffset for the date, and adjust it to the offset found above.
var dto = new DateTimeOffset(dt).ToOffset(offset);

// Serialize to json
var json = JsonConvert.SerializeObject(dto, new JsonSerializerSettings
    {
        DateFormatHandling = DateFormatHandling.MicrosoftDateFormat,
    });


// The json should now contain the correct time and offset information.
// For example,  "\/Date(1358789156229-0500)\/"

Now hopefully you will find that the javascript controls you are using will honor the offset and apply it appropriately. If not, then the rest of the problem is specific to the control you are using.

like image 60
Matt Johnson-Pint Avatar answered Sep 23 '22 16:09

Matt Johnson-Pint