【问题标题】:Date from angular(timezone) to server (utc) then utc to Timezone从角度(时区)到服务器(UTC)然后从UTC到时区的日期
【发布时间】:2015-12-22 14:05:30
【问题描述】:

我在获取正确时区的日期时遇到问题。

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

因此,日期从 Angular 应用程序(“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”,我将日期转换为字符串,然后再转换回日期时间格式,但似乎没有任何效果。

我能做什么?

【问题讨论】:

    标签: angularjs date asp.net-web-api timezone utc


    【解决方案1】:

    一些事情:

    • 您的示例不完整,因此我只能推测某些方面。最好显示两面,包括如何在 Angular 中加载和解析数据,以及数据在网络上的样子。

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

    • 当序列化为 ISO8601 格式时,DateTime 对象与 Kind 属性中的关联 DateTimeKind 相结合。

      • 如果KindUtc,则ISO8601 字符串将以Z 结尾。
      • 如果KindLocal,则ISO8601 字符串将以该时间戳的机器本地偏移量结尾,例如-08:00
      • 如果 KindUnspecified,则 ISO8601 字符串将没有 Z 或偏移量 - 这意味着它不能明确表示特定的时间点。

      这最终是错误的原因。您正在将DateTime 转换为另一个时区,从而将其保留为Unspecified 种类,然后在没有偏移的情况下对其进行序列化 - 因此在客户端(可能)在浏览器的本地时区中被解释。

    • 更好的方法是使用DateTimeOffset 而不是DateTime。那你就不用担心Kind了,偏移量总是存在的。如果您将 bookview.StartDateTime 更改为 DateTimeOffset 类型,您可以执行以下操作来解决问题:

        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 的调用——对此要非常小心。如果源种类为Unspecified,则将其视为Local。因此,计算机的本地时区反映在转换后的值中。最好完全避免ToUniversalTimeToLocalTime。仅使用TimeZoneInfo 上的转换方法。

    • ToolsHelper.OlsonTimeZoneToTimeZoneInfo 也不是我们所知道的。但我假设它执行类似于this one 的 CLDR 映射。但是,如果您仍然使用奥尔森时区,更好的方法是根本不使用TimeZoneInfo。相反,请使用 Noda Time,因为它原生支持 tzdb 时区。

    【讨论】:

    • 非常感谢您的帮助,我学到了新知识并理解了问题,我完全按照您所说的解决了问题,转换为 DateTimeOffset,现在就像一个魅力一样工作。耶稣祝福你。
    猜你喜欢
    • 2016-10-10
    • 1970-01-01
    • 2020-07-18
    • 2012-10-29
    • 2011-08-10
    • 2021-11-09
    • 2018-03-05
    • 1970-01-01
    • 2019-06-05
    相关资源
    最近更新 更多