代码之家  ›  专栏  ›  技术社区  ›  Mjeduar

从角度(时区)到服务器(utc),然后从utc到时区的日期

  •  4
  • Mjeduar  · 技术社区  · 9 年前

    我有一个问题,在正确的时区找回日期。

    首先,在本地机器上,一切都很好,但在服务器上不行:服务器托管在美国,客户机大多在澳大利亚。

    因此,一个日期从angular app(“12/23/2015 11:00:00 AM”)发送到服务器,服务器将日期作为utc存储在数据库中,直到此时一切正常(我检查了,日期存储在正确的utc中)

    book.StartDateTime = TimeZoneInfo.ConvertTimeToUtc(DateTime.SpecifyKind(book.StartDateTime.Value, DateTimeKind.Unspecified), ToolsHelper.OlsonTimeZoneToTimeZoneInfo(locationDetails.TimeZone)); // book.CreatedDate.Value.ToUniversalTime();
    

    问题是:

    当客户端请求存储在数据库中的某些日期时。存储在数据库中的日期将返回给客户端,如下所示:

     bookview.StartDateTime = TimeZoneInfo.ConvertTimeFromUtc(DateTime.SpecifyKind(bookli.StartDateTime.Value, DateTimeKind.Utc), ToolsHelper.OlsonTimeZoneToTimeZoneInfo(deCompany.TimeZone));
    

    我检查了一下,现在的日期是“12/23/2015 11:00:00 AM”->转换就在服务器中(在服务器端我放了一个日志),

    但角度显示为“12/23/2015 10:00:00 PM”

    所以很明显,问题是api何时将日期传输到客户端,或者何时转换为JSON

    我尝试了不同的方法,但什么都不起作用,我删除了“DateTime.SpecifyKind”,我将日期转换为字符串,然后返回到DateTime格式,似乎什么也不起作用。

    我能做什么?

    1 回复  |  直到 9 年前
        1
  •  6
  •   Community clintgh    3 年前

    一些事情:

    • 你的例子不完整,所以我只能推测一些方面。最好展示双方,包括如何在Angular中加载和解析数据,以及数据在网络上的样子。

    • 您不应该以特定于区域设置的格式来回发送日期,如 "12/23/2015 11:00:00 AM" 。您可以在UI中使用这些,但它们不适合通过网络(在JSON中)。相反,您应该使用 ISO8601 / RFC3339 例如 "2015-12-23T11:00:00Z" 。(如果您正在使用WebAPI,可能已经在这样做了。)

    • A. DateTime 对象与关联的 DateTimeKind Kind 所有物

      • 如果 友善的 Utc ,则ISO8601字符串将以 Z .
      • 如果 友善的 Local ,则ISO8601字符串将以该时间戳的机器本地偏移量结束,例如 -08:00 .
      • 如果 友善的 Unspecified ,则ISO8601字符串将没有 Z 或偏移-这意味着它不能明确地表示特定的时刻。

      这最终是错误的原因。您正在转换 日期时间 到另一个时区 未指定 kind,然后在没有偏移量的情况下进行串行化-因此在客户端,它(可能)在浏览器的本地时区进行解释。

    • 更好的方法是使用 DateTimeOffset 而不是 日期时间 那你就不用担心了 友善的 ,并且偏移始终存在。如果您更改 bookview.StartDateTime 日期时间偏移 键入,您可以这样做来解决问题:

        DateTimeOffset dto = new DateTimeOffset(bookli.StartDateTime.Value, TimeSpan.Zero);
        bookView.StartDTO = TimeZoneInfo.ConvertTime(dto, ToolsHelper.OlsonTimeZoneToTimeZoneInfo(deCompany.TimeZone));
      

      这将确保偏移量在数据中保持不变。

    • 在客户端,请注意如何解析ISO字符串。如果它加载到 Date 对象,则它确实会被转换为客户端的时区。相反,你可以看看 moment.js 用于客户端时间格式。特别是,使用 moment.parseZone 以保持该值与显示的偏移量相同。例如:

        var s = moment.parseZone("2015-12-31T11:00:00+00:00").format("L LT"); // "12/31/2015 11:00 AM"
      
    • 在注释代码中,您还显示了对 DateTime.ToUniversalTime -对此要非常小心。如果源类型为 未指定 ,它被视为 地方的 因此,计算机的本地时区反映在转换后的值中。最好避免 ToUniversalTime ToLocalTime 完全仅在上使用转换方法 TimeZoneInfo .

    • ToolsHelper.OlsonTimeZoneToTimeZoneInfo 我们也不知道。但我假设它执行的CLDR映射类似于 this one 然而,如果你使用的是奥尔森时区,最好的方法是不要使用 时区信息 完全相反,使用 Noda Time ,具有对tzdb时区的本地支持。