【问题标题】:Force JSON.NET to include milliseconds when serializing DateTime (even if ms component is zero)强制 JSON.NET 在序列化 DateTime 时包含毫秒(即使 ms 组件为零)
【发布时间】:2013-08-14 03:15:41
【问题描述】:

我正在使用 JSON.NET 直接从对象实例序列化 DateTime 值(不使用带有格式化程序的 DateTime.ToString())。

有没有办法强制 JSON.NET 在序列化中包含毫秒,即使 DateTime 的毫秒部分为零?

背景:对于这个 JSON 端点,我有一个非常慢的 Web 服务使用者。条件逻辑对消费者来说很昂贵,所以我想每次都提供相同的数据格式。

【问题讨论】:

  • 解释一下导致您想要这样做的一系列情况可能是个好主意

标签: c# json datetime serialization json.net


【解决方案1】:

我在使用 JsonWriter 时遇到了这个问题并需要解决它,因为我们观察到诸如 Day.js 之类的 Javascript 日期库更喜欢毫秒而不是 3 位数。这个问题使我得到了解决方案,所以我想分享它以防其他人有像我这样的用例:

StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
using (JsonWriter writer = new JsonTextWriter(sw)) {
    writer.Formatting = Newtonsoft.Json.Formatting.None;
    writer.DateFormatString="yyyy'-'MM'-'dd'T'HH':'mm':'ss.fff''";
    writer.WriteStartObject();

    DateTime? date = new DateTime(2021,12,30,23,59,40,250);
    writer.WritePropertyName("Date1");
    writer.WriteValue(date);

    date = new DateTime(2021, 12, 30, 23, 59, 40, 555);
    writer.WritePropertyName("Date2");
    writer.WriteValue(date);

    date = new DateTime(2021, 12, 30, 23, 59, 40, 0);
    writer.WritePropertyName("Date3");
    writer.WriteValue(date);

    date = null;
    writer.WritePropertyName("DateNULL");
    writer.WriteValue(date);
    writer.WriteEndObject();
}
Console.WriteLine(sb.ToString());

这会产生:

{
    "Date1": "2021-12-30T23:59:40.250",
    "Date2": "2021-12-30T23:59:40.555",
    "Date3": "2021-12-30T23:59:40.000",
    "DateNULL": null
}

我需要添加的重要行是:

writer.DateFormatString="yyyy'-'MM'-'dd'T'HH':'mm':'ss.fff''";

【讨论】:

    【解决方案2】:

    对于任何找到此答案并希望解析此类 .NET 默认格式时间戳的 Java 人,我想指出一种用于解析格式的 Java 8 (java.time.*) 方法:

    public static final DateTimeFormatter FORMATTER =
        new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd'T'HH:mm:ss")
                                      .appendFraction(ChronoField.MILLI_OF_SECOND, 0, 3, true)
                                      .toFormatter();
    ...
    LocalDateTime ldt = LocalDateTime.parse(dateString, FORMATTER);
    

    这表示期望 0-3 位小数毫秒,true 是期望的小数点。例如,它将“.47”正确解释为 470 毫秒。

    【讨论】:

      【解决方案3】:

      我们在我当前的项目中遇到了同样的问题。我们正在使用 Web API(以及 JSON.Net)来实现 REST API。我们发现,在序列化DateTime 对象时,JSON.Net 会忽略毫秒的尾随零,或者如果它是零,则完全忽略日期的毫秒。我们的客户期望一个固定长度的日期时间字符串,精确到毫秒的 3 位数字。我们通过在Application_Start() 中执行以下操作来修复它:

      JsonSerializerSettings settings = HttpConfiguration.Formatters.JsonFormatter.SerializerSettings;
      IsoDateTimeConverter dateConverter = new IsoDateTimeConverter 
      { 
          DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.fff'Z'" 
      };
      settings.Converters.Add(dateConverter);
      

      如果您不使用 Web API,您可以通过创建JsonSerializerSettings 的新实例,如上所示将IsoDateTimeConverter 添加到其中,然后将序列化程序设置传递给JsonConvert.SerializeObject() 来执行相同的操作。

      注意:如果您要序列化 ​​DateTimeOffset 或本地 DateTime 并且想要包含时区偏移量,请将上述格式中引用的 'Z' 替换为未引用的 K。 有关详细信息,请参阅文档中的 Custom Date and Time Format Strings

      【讨论】:

      • 您使用我的性能代码的方法实际上需要大约 153 毫秒来解析。看来性能很重要,这就是我提出它的原因。他们说一个人会在大约 200 毫秒后注意到延迟,因此您最终只剩下大约 43 毫秒来考虑网络使用、数据库访问等问题。
      • 我的回答只是试图解决 OP 关于如何让 JSON.Net 在格式化日期时始终包含毫秒的问题。它不做任何形式的性能声明。
      • 是的,没关系,我只是在添加一些信息,可能对 OP 或以后的其他人有所帮助。
      • @jrummell 单引号表示格式中文字字符的开始和结束,即那些不打算用日期的一部分替换的字符。在这里,这并不重要,因为文字字符 -T:Z 都不会与格式化说明符字符混淆。另一方面,例如,如果您想将文字 M 放在某个格式中,您肯定需要引用它。有关详细信息,请参阅文档中的 Custom Date and Time Format Strings
      • @jrummel:即使在这种情况下,文字分隔符也很重要。例如,如果您当前的文化是"it-IT",那么如果您不处理":" 通过引用分隔符作为文字。
      猜你喜欢
      • 2021-07-29
      • 2018-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-11
      相关资源
      最近更新 更多