【问题标题】:Problem transmitting date over the network通过网络传输日期的问题
【发布时间】:2019-05-28 18:44:59
【问题描述】:

我有一个 MVC 应用程序,它以 JSON 格式从美国的服务器发送日期值,并显示在智利的 PC 中。

服务器端在控制器中有这个动作:

   public async Task<ActionResult> GetFacturas(Models.DataTableAjaxPostModel model)
    {
        // Some other code in between
        // ----
        return Json(fecha);   // fecha has the value of 2019-04-16 00:00:00
    }

通过使用 Chrome 开发工具,我看到 JSON 对象中收到的日期为 1555383600000。

通过使用https://www.epochconverter.com/ 网站,我将该日期翻译成人类可读的格式,我看到它是:

GMT: Tuesday, 16 April 2019 3:00:00
Your time zone: Monday, 15 April 2019 23:00:00 GMT-04:00

即使 MVC 控制器的日期为 2019-04-16 00:00:00,似乎 Json 对其进行序列化时,它也使用 -3 时区转换为 GMT,因此,客户端计算机最终收到了 GMT 日期,然后应用 -4 操作将日期转换回本地时间。

操作系统配置为-4时区,MVC应用在web.config文件中是这样配置的:

<globalization culture="es-CL" uiCulture="es-CL" />

如何避免这个问题?

编辑:

"fecha" 变量是从数据库返回的 DateTime 对象,这样:

var fecha = db.Entity.Select(f => f.DatetimeField).FirstOrDefault();

当然我简化了查询,但事实是“fecha”在返回函数之前是一个DateTime对象,其值为2019-04-16 00:00:00。

问候

詹姆

【问题讨论】:

  • 用户将看到服务器时间,无论其位置如何。如果您需要当地时间,则需要将日期时间返回为 .ToLocalTime().DateTime。您的问题不反映您所期望的。
  • @BalajiBirajdar - ToLocalTime 使用 服务器 的时区。它不了解客户的本地时区。此外,您假设 fetchaDateTimeOffset 类型,但这在问题中没有说明。
  • @jstuardo - 你的问题并没有给我们一个完整的画面。我们需要知道您正在序列化的fetcha 变量的数据类型,并且我们还需要查看如何实例化它的示例,以及序列化形式的显示方式。然后我们需要查看您的客户端代码以了解您如何反序列化它。请阅读帮助中心的How to create a Minimal, Reproducible Example。此外,您应该了解时区与文化设置无关。它们是完全不同的概念。
  • @MattJohnson 我已经编辑了这个问题。您可以通过使用我拥有的值创建一个 DateTime 对象来简单地重现它,然后将其作为 Json 对象返回。我没有直接反序列化,因为我使用的是 DataTable jquery 插件。不过,没关系。事实是,如果我使用epochconverter.com 页面查看客户端收到的值,它比实际时间少1 小时。这表明这与显示时间的客户端无关。 Json 对象错误地序列化了日期和时间。
  • @MattJohnson 确切的问题可能是,为什么 Newtonsoft Json 对象使用时区 -3 而不是操作系统中配置的 -4 将 DateTime 对象序列化为 UTC。这导致示例中的日期和时间被传输为 2019-04-16 03:00:00... 因此,在反序列化时,使用时区 -4,导致日期和时间显示为 2019- 04-15 23:00:00。有没有办法将 Newtonsoft Json 对象配置为使用正确的时区?

标签: asp.net json asp.net-mvc datetime timezone


【解决方案1】:

我假设 JSON 中的值类似于 "/Date(1555383600000)/",它是旧的 JSON date format。使用这种格式,当DateTime 值的.Kind 属性为DateTimeKind.LocalDateTimeKind.Unspecified 时,将应用服务器的本地时区。

即使存储在数据库中的值是 UTC,EF 也无法知道这一点,因此它被设置为未指定。你可以自己设置:

fetcha = DateTime.SpecifyKind(fetch, DateTimeKind.Utc);

现在您会发现该值被序列化为"/Date(1555372800000)/"

当前版本的 ASP.Net 和 Newtonsoft.Json 改用 ISO 8601 格式。无需对您的代码进行任何更改,您的值将基于 .Kind 属性进行序列化,如下所示:

  • DateTimeKind.Unspecified, as"2019-04-16T00:00:00.0000000"`
  • 使用DateTimeKind.Utc,作为"2019-04-16T00:00:00.0000000Z"
  • 使用DateTimeKind.Local,作为"2019-04-16T00:00:00.0000000-03:00"(使用服务器的tz 偏移)

您可以使用DateFormatHandling setting 在两种格式之间切换,但我建议将其保留为默认值IsoDateFormat。另见Serializing Dates in JSON

客户端反序列化也是一个因素。如果您收到一个时间戳(使用旧格式),则该时间戳与 UTC 对齐。如果您收到一个字符串(使用新格式),则时间戳受字符串中偏移量的影响,如果没有提供偏移量,则受本地浏览器时区影响。此外,JavaScript 中的Date 对象有许多只能使用浏览器本地时区的函数。

考虑到所有因素,在不受时区影响的情况下,很难获得仅日期值以进行端到端序列化。您可以尝试上述方法,但如果您确实只想保存、恢复、显示和传输相同的仅日期值,那么您也可以考虑发送不带时间的字符串,如"2019-04-16"

return Json(fetch.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture"));

【讨论】:

  • 数据库中的日期和时间是客户端本地时间(智利时间)。此外,我正在使用最新版本的 Newtonsoft 库和最新版本的 MVC,所以我想知道为什么使用旧格式。我正在使用 Controller.Json 方法将 JsonResult 返回给客户端。您的意思是,在该调用之前,我必须将“fecha”变量重新分配给对 SpecifyKind 的调用?我曾考虑过传输一个字符串,但我认为这应该是最后一个资源,因为 DataTable 插件需要一个日期和时间。如果我得到一个字符串而不是日期,我需要为 DataTable 插件编写一个自定义格式化程序,
  • 我终于用.ToString("s") 到了序列化前的日期。这样,客户端可以在应用日期格式之前正确反序列化为日期和时间对象,然后才能在 DataTable 中显示。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多