ParseExact 无法解析 RFC 3339 Internet Date/Time 格式的字符串

ParseExact cannot parse a string in RFC 3339 Internet Date/Time format

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 Date/Time 格式中的任何日期都应该有效。现在来自规范 here 部分 5.6

time-secfrac    = "." 1*DIGIT

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

有什么解决办法吗?

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

The fffffff custom format specifier represents the seven most significant digits of the seconds fraction; that is, it represents the ten millionths of a second in a date and time value.

在你的第一个例子中

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

您使用的 fffffffff 对于 .NET 自定义日期和时间格式字符串来说更精确

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

The "fffffff" custom format specifier represents the seven most significant digits of the seconds fraction; that is, it represents the ten millionths of a second in a date and time value.

Although it's possible to display the ten millionths of a second component of a time value, that value may not be meaningful. The precision of date and time values depends on the resolution of the system clock.

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

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

  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, "");
    DateTime parsedDate = DateTime.ParseExact(input, format, null);