【问题标题】:JSON Date Serialization and Time ZonesJSON 日期序列化和时区
【发布时间】:2013-01-20 18:15:51
【问题描述】:

我在使用 JSON 序列化对象在客户端浏览器上显示正确日期时遇到问题。用户能够定义他们想要查看数据的时区。鉴于此,我将 UTC 日期转换为服务器上用户的时区。然后我想通过 JSON 将日期/时间(已经转换为他们定义的时区)序列化到浏览器。

看起来很简单,但是我一直在使用的 JSON 序列化程序严重影响了我的日期。服务器使用 UTC,客户端使用 Central (-6)。即使我将 DateTime.Kind 指定为未指定,日期也会被调整(-12 小时)。

.NET 不知何故知道客户端浏览器所在的时区和服务器所在的时区,并且它从我的日期/时间中否定 -6,即使我已经根据用户的全局设置调整了时间并设置日期的种类未指定。如何让 JSON 序列化程序不尝试调整我的日期?

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 日期似乎可以使用,但我无法使用它们,因为我有需要旧版 Microsoft 格式的 3rd 方控件...它会调整我的时区。

【问题讨论】:

  • 这不是您问题的答案,但如果您想将日期逻辑推送到 javascript - 请查看 moment.js momentjs.com

标签: .net json datetime timezone json.net


【解决方案1】:

当您尝试控制偏移量时,不要依赖DateTimeKind.Unspecified。它有一些怪癖,通常被解释为Unspecified == Local。让 Json.Net 专门编码正确偏移量(无论 ISO 或 MS 格式)的唯一方法是将其传递给 DateTimeOffset 而不是 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)\/"

现在希望您会发现您正在使用的 javascript 控件将遵守偏移量并适当地应用它。如果不是,那么剩下的问题就是您使用的控件所特有的。

【讨论】:

  • 好吧,我尝试了你的想法。 +1 是个好主意。不幸的是,我正在使用的 Kendo Grid(第 3 方控件)不适用于偏移信息 :( 我的最后一个想法是可能创建自己的日期转换器并将其传递给 JSON.NET。然后我的日期在服务器端转换到用户所需的时区将通过 JSON 传递,而无需 .NET 自动调整我的时间。
  • @BillChristenson 你应该阅读this article。作者描述了如何处理剑道网格中的日期。他还展示了如何接受 ISO 格式的日期输入 here,恕我直言,这比使用 microsoft 日期格式要好得多。
  • 是的,我读过那些博客。我正在使用 AJAX/JSON MVC 服务器包装器,它与他使用的实现不同。如果可以的话,我也不想调整他们的 .js 文件。我会让你们知道我的自定义 JSON.NET 转换器是如何工作的。我快完成了。
  • 像我展示的那样将其转换为正确的 DateTimeOffset 后作为 ISO 字符串传递。然后在客户端上,使用 MomentJS 之类的库将字符串解析为 Javascript 日期,而不会妨碍本地偏移量。然后将该日期绑定到您的控件。
【解决方案2】:

这是关于我所处的确切情况的长时间讨论。http://www.telerik.com/community/forums/aspnet-mvc/grid/grids-and-dates.aspx

底线,如果您使用 Microsoft JSON 日期格式,它将始终以 UTC 格式的日期反映为距 1970 年 1 月 1 日 UTC 的毫秒数(滴答声)。我无法在服务器上将时间自动转换为本地时间,并通过 JSON 将它应该下降的时间发送到 Kendo Grid,因为 Kendo Grid 控件将 JS 中的刻度中的日期实例化为 UTC。显示此日期时,会自动将值转换为浏览器的本地时区。

从服务器显示我的服务器转换后的日期值的唯一方法是通过 JSON 将日期作为字符串发送到客户端。

【讨论】:

  • 你的剑道链接坏了,你有好的链接吗...这里有同样的问题。
【解决方案3】:

我们也遇到了这个问题。正如您所注意到的,问题实际上发生在客户端。通过在网格中使用请求结束处理程序,您可以将日期转换回 UTC。在此处找到示例:

http://www.kendoui.com/code-library/mvc/grid/using-utc-time-on-both-client-and-server-sides.aspx

【讨论】:

    猜你喜欢
    • 2012-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-13
    • 2012-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多