在本地机器上一切都很冷,一切正常,但不在服务器中:服务器托管在美国,客户大多在澳大利亚.
所以从角度应用程序(“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”,我将日期转换为字符串然后回到日期时间格式,似乎没有任何工作.
我能做什么?
解决方法
>你的例子不完整,所以我只能推测某些方面.最好显示双方,包括如何在Angular中加载和解析数据,以及数据在线上的样子.
>您不应该以特定于语言环境的格式来回发送日期,例如“12/23/2015 11:00:00 AM”.您可以在UI中使用它们,但它们不适合通过线路(在您的JSON中).相反,您应该使用ISO8601/RFC3339,例如“2015-12-23T11:00:00Z”. (如果您使用的是WebAPI,则可能已经在执行此操作.)
>序列化为ISO8601格式的DateTime对象与Kind属性中的关联DateTimeKind耦合.
>如果Kind是Utc,则ISO8601字符串将以Z结尾.
>如果Kind是Local,则ISO8601字符串将以该时间戳的机器本地偏移量结束,例如-08:00.
>如果Kind未指定,则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.因此,计算机的本地时区将反映在转换后的值中.最好完全避免ToUniversalTime和ToLocalTime.仅使用TimeZoneInfo上的转换方法.
> ToolsHelper.OlsonTimeZoneToTimeZoneInfo也不是我们所知道的.但是我会假设它执行类似于this one的CLDR映射.但是,如果你正在使用Olson时区,那么更好的方法是根本不使用TimeZoneInfo.相反,使用Noda Time,它具有对tzdb时区的本机支持.