当存储为 UTC 时,如何全局序列化和反序列化 Date 与 DateTime?
Posted
技术标签:
【中文标题】当存储为 UTC 时,如何全局序列化和反序列化 Date 与 DateTime?【英文标题】:How do I globally serialize and deserialize Date vs DateTime when stored as UTC? 【发布时间】:2019-04-26 18:10:48 【问题描述】:在我的 SQL Server 数据库中,我将所有 DateTime
值存储为 UTC。但是,在某些情况下,我不关心时间,例如某个随机时区的用户使用 DatePicker 选择日期。在这些情况下,存储为 Date
与 DateTime
似乎更有意义。
当从数据库中获取日期并通过 Web API 将它们发送到我的 Angular 应用程序时,我想确保我的所有 DateTime
值都以某种方式格式化,以便 Angular 知道它们是 UTC 日期并显示为当地时间,所以我将此添加到 Web API 以在末尾添加“Z”:
// Set all dates to UTC
config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new IsoDateTimeConverter
DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"
);
这可行,但问题是这种转换也适用于我的Date
值。当日期从数据库中提取到 C# 中时,它们位于 DateTime
变量中,因为 C# 没有 Date
变量,因此它们得到一个午夜的时间。因此,如果 CST 中的用户选择 2018 年 11 月 24 日的日期,当它往返于数据库并返回时,它将变为 2018 年 11 月 23 日(下午 6:00 的时间被截断)。
如何防止这种行为?一些想法可能是:
-
有条件地应用 IsoDateTimeConverter?
我认为这在全球范围内是不可能的,因为我无法判断它是存储在 C# DateTime 变量中的
Date
还是 DateTime
值。
将 SQL Server 中的数据类型更改为DateTime
?
我认为这也行不通,因为即使我根据数据的来源存储时间,对于其他时区的用户来说,这难道不是错误的吗?
【问题讨论】:
顺便说一句,您可以将 DateTimeFormat "o" 用于 ISO8601 格式日期。当然,这对你的问题没有多大帮助。 由于您使用的是 JSON.NET,因此您可以仅在这些日期字段上使用 [JsonConverter] 属性。我很想看看是否有更好的解决方案。 @John,我想过这样做。如果可能的话,我更愿意在全球范围内处理它。如果我最终这样做了,您是否知道该属性是否会覆盖全局 IsoDateTimeConverter,以便我仍然可以将全局转换器用于所有其他 DateTime 值? 我认为应该这样做,但不要强迫我这样做。 首先,您似乎将UTC 与ISO8601 混淆了。第一个是特殊的时区,第二个是日期/时间/日期时间和周期的字符串表示的标准规范。其次,如果您正在使用 Sql Server,you should be usingDateTime2
, and not DateTime
.
【参考方案1】:
根据@John 的建议,我创建了一个自定义的 IsoDateTimeConverter:
public class DateConverter : IsoDateTimeConverter
public DateConverter()
DateTimeFormat = "MM-dd-yyyy";
并手动将其应用于每个 Date
值,该值会覆盖我添加到 Web API 配置中的全局转换器。
[JsonConverter(typeof(DateConverter))]
public System.DateTime StartDate get; set;
我仍然希望有一种全球性的方式来处理这个问题,而不必将属性应用于每个 Date
属性,但这至少让我摆脱困境。
对 Angular 用户的警告。我最初尝试使用格式“yyyy-MM-dd”,但它必须将其解释为 UTC,因为在向用户显示日期时我遇到了同样的问题。将其更改为“MM-dd-yyyy”虽然有效。见https://github.com/angular/material2/issues/6111
【讨论】:
我认为您找到了正确的解决方案。如果您的类为Date
与 DateTime
使用不同的数据类型来镜像数据库,那么您可以在全局配置中使用针对该类型的自定义转换器(与 DateTime 的其他转换器一起)并且您不需要属性.但是由于它们使用相同的数据类型,您仍然需要某种属性来区分它们,以便能够在全局范围内应用转换器(例如,使用自定义合约解析器)。所以你不妨直接使用[JsonConverter]
属性直接应用转换器,跳过解析器。以上是关于当存储为 UTC 时,如何全局序列化和反序列化 Date 与 DateTime?的主要内容,如果未能解决你的问题,请参考以下文章