【问题标题】:ParseExact cannot parse a string in RFC 3339 Internet Date/Time formatParseExact 无法解析 RFC 3339 Internet 日期/时间格式的字符串
【发布时间】:2019-10-22 14:04:56
【问题描述】:

C# 似乎无法以有效的 RFC 3339 格式解析时间:

DateTime.ParseExact("2019-12-31T00:00:00.123456789+01:00", "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffffzzz", null)

这一行抛出异常,而这一行工作正常:

DateTime.ParseExact("2019-12-31T00:00:00.1234567+01:00", "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffzzz", null)

所以似乎毫秒有限制,但我找不到任何相关文档。这是应该的吗?


想要解析这个日期的原因是我有一个输入日期字段。我们使用 OAS (Swagger) date-time 格式,它非常清楚地表明 RFC 3339 Internet 日期/时间格式中的任何日期都应该是有效的。现在来自规范here 第 5.6 节

time-secfrac    = "." 1*DIGIT

据我了解,这意味着最多应允许 9 位数字,并且要 100% 兼容,我们必须允许这些输入,但 C# 似乎甚至不支持。

关于如何解决它的任何想法?

【问题讨论】:

  • 很简单,.NET 最多支持 7 位毫秒
  • 恕我直言,1*DIGIT 表示 1 个或多个数字。
  • 在我的系统上,DateTime.Parse("2019-12-31T00:00:00.123456789+01:00", CultureInfo.InvariantCulture) 实际上可以正常工作并正确解析值(DateTimeOffset 也是如此),使用它支持的所有毫秒精度,即使似乎没有办法指定它的明确格式。所以一种可能性是一个简单的正则表达式匹配来验证你有这个,然后在没有Exact的情况下解析它。
  • 顺便说一句,RFC 3339 遵循 ISO8601 规范——该规范指出小数的位数不受标准限制,但需要通信双方同意。
  • 是的。 1*DIGIT 表示至少 1 位,最多不限位数。 tools.ietf.org/html/rfc2234#section-3.6

标签: c# datetime openapi rfc3339


【解决方案1】:

根据MSDN 规范,您只能使用fffffff

fffffff 自定义格式说明符代表七个最 秒小数的有效数字;也就是说,它代表 日期和时间值的百万分之一秒。

在你的第一个例子中

DateTime.ParseExact("2019-12-31T00:00:00.123456789+01:00", "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffffzzz", null)

您正在使用fffffffff,这对于 .NET 自定义日期和时间格式字符串更为精确

【讨论】:

    【解决方案2】:

    据我所知,.NET 支持以毫秒为单位的七个最高有效数字,即The "fffffff" custom format specifier 用于。

    “fffffff”自定义格式说明符代表七个最 秒小数的有效数字;也就是说,它代表 日期和时间值的百万分之一秒。

    虽然可以显示百万分之一秒 时间值的组成部分,该值可能没有意义。这 日期和时间值的精度取决于分辨率 系统时钟。

    这意味着您提供的不有意义的数据不受 .NET Framework 支持。我强烈建议不要这样做。

    【讨论】:

    • .Net 不完全支持 RFC 3339 有点令人失望,虽然通常有这样的精度毫无意义,但它仍然是规范......
    • 看起来我误解了规范,实际上是无限位数
    【解决方案3】:

    除了其他答案中的信息,如果您无法更改输入但仍想解析它,您可以使用以下解决方案之一:

    1. 如果您的输入始终采用相同的格式(即,有 9 秒小数位),您可以删除两个额外的并继续解析它:

      string input = "2019-12-31T00:00:00.123456789+01:00";
      input = input.Remove(27, 2);
      // TODO: parse `input`.
      
    2. 如果您事先不知道秒小数位数,您可以使用以下内容:

      string input = "2019-12-31T00:00:00.123456789+01:00";
      string format = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFFzzz";
      
      var regEx = new Regex(@"^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{1,7})\d*");
      input = regEx.Replace(input, "$1");
      DateTime parsedDate = DateTime.ParseExact(input, format, null);
      

    【讨论】:

    • 没有真正的理由来计算和指定fs 的确切数量。 FFFFFFF 说明符将处理可变数量的数字。
    • @JeroenMostert 你是对的。谢谢!更新了答案。
    • 好吧,实际上我似乎误解了规范,并且由于某种原因允许无限数量的数字,所以我只是将数字限制在 .net 支持的最大可能范围内,即7,这样就够了:)
    猜你喜欢
    • 1970-01-01
    • 2020-08-24
    • 1970-01-01
    • 1970-01-01
    • 2017-03-15
    • 2011-08-27
    • 1970-01-01
    • 1970-01-01
    • 2023-03-12
    相关资源
    最近更新 更多