当存储为 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 选择日期。在这些情况下,存储为 DateDateTime 似乎更有意义。

当从数据库中获取日期并通过 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 using DateTime2, 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

【讨论】:

我认为您找到了正确的解决方案。如果您的类为 DateDateTime 使用不同的数据类型来镜像数据库,那么您可以在全局配置中使用针对该类型的自定义转换器(与 DateTime 的其他转换器一起)并且您不需要属性.但是由于它们使用相同的数据类型,您仍然需要某种属性来区分它们,以便能够在全局范围内应用转换器(例如,使用自定义合约解析器)。所以你不妨直接使用[JsonConverter]属性直接应用转换器,跳过解析器。

以上是关于当存储为 UTC 时,如何全局序列化和反序列化 Date 与 DateTime?的主要内容,如果未能解决你的问题,请参考以下文章

PHP数组序列化和反序列化

理解PHP数组的序列化和反序列化

C#中如何实现多个观测数据对象序列化和反序列化?

leetcode-449序列化和反序列化二叉搜索树

如何序列化和反序列化 JavaScript 对象?

利用php的序列化和反序列化来做简单的数据本地存储