c# - 当 UTC 与时区偏移一起使用时,DateTime.Parse 方法中是否存在错误?

标签 c# datetime iso8601

Microsoft 文档指出,在 DateTime 结构的其他字符串表示形式中,DateTime.Parse(string) 符合 ISO 8601 并接受时区偏移量的协调世界时 (UTC) 格式。

当我运行以下单元测试用例时,DateTime.Parse(string) 和 DateTime.TryParse(string, out DateTime) 接受源字符串末尾的附加字符。这似乎是一个错误。当附加多个附加字符时,该方法无法正确解析字符串。

[Theory]
[InlineData("2020-5-7T09:37:00.0000000-07:00")]
[InlineData("2020-5-7T09:37:00.0000000-07:00x")]
[InlineData("2020-5-7T09:37:00.0000000-07:00xx")]
[InlineData("2020-5-7T09:37:00.0000000Z")]
[InlineData("2020-5-7T09:37:00.0000000Zx")]
public void TestParse(string source)
{
    DateTime dt = DateTime.Parse(source);
    Assert.True(dt != null);
    bool b = DateTime.TryParse(source, out dt);
    Assert.True(b);
}

编写此单元测试用例是为了简化我的代码并说明我所看到的行为(我认识到应该以不同的方式处理预期的失败)。

测试 1 和 2 通过,第三个测试(带有“xx”后缀)失败。在我看来,第二个测试(带有“x”后缀)应该失败。

如果未提供时区指示符,则测试 4 通过,测试 5 失败。这似乎是正确的行为。

我想知道是否有人遇到过这种情况,如果是的话,是否普遍认为这是一个错误?

最佳答案

就我个人而言,这对我来说似乎是一个错误......

2020-5-7T09:37:00.0000000-07:00x 是一个有效的 ISO 8601 日期,末尾有一个无效的任意字符,它会错误地解析而不会出现错误,其中两个任意字符似乎正确失败。

似乎发生的事情如下

  1. ParseISO8601 中解析时它在 ParseTimeZone 中获取正确的时区信息-07:00
  2. 这使得 str 具有最后一个索引 1
  3. 然后它会检查 str.Match('#') 前缀会增加索引(我认为这是错误)。
  4. 此时,由于索引位于字符串末尾,因此在后续检查中假定解析已完成

比赛摘录

我的评论

internal bool Match(char ch)
{
    if (++Index >= Length) // reaches the end of the string here
    {
        return false;
    }
    ...
}

上面的方法返回false,但是它增加了索引!这在事情的计划中看起来非常奇怪。

它的设计目的似乎是检查当前字符的哈希值,然后空终止,如果还有其他内容则失败。

摘自 ParseISO8601

str.SkipWhiteSpaces();
if (str.Match('#'))  // mine... check hash ... no
{
   if (!VerifyValidPunctuation(ref str))
   {
      result.SetFailure(ParseFailureKind.Format, "Format_BadDateTime", null);
      return false;
   }
   str.SkipWhiteSpaces();
}
if (str.Match('\0')) // mine... check null termination ... no
{
   if (!VerifyValidPunctuation(ref str))
   {
      result.SetFailure(ParseFailureKind.Format, "Format_BadDateTime", null);
      return false;
   }
}
if (str.GetNext()) // mine... get anything else, if found fail
{
   // If this is true, there were non-white space characters remaining in the DateTime
   result.SetFailure(ParseFailureKind.Format, "Format_BadDateTime", null);
   return false;
}

注意:这似乎发生在我测试过的每个框架中。

简而言之,它完全忽略日期末尾的任何任意字符,但是,如果还剩下 2 个字符,它会按预期运行,因为它会减少匹配检查中的索引。

internal bool Match(char ch) {
    if (++Index >= len) {
        return (false);
    }
    if (Value[Index] == ch) {
        m_current = ch;
        return (true);
    }
    Index--;
    return (false);
}

更新 1

我已将其报告为 GitHub 上的运行时错误,可以在此处进行跟踪

DateTime.Parse ISO 8601 allowing extra arbitrary character at the end of the date #46477

更新2

这已被正式标记为运行时错误,并且已计划在 .Net 6 中进行修复

我还没有时间构建运行时来检查它实际在做什么,但从评论看来,当它拉动时区时,当前索引增加了 1 太多,并且匹配错误地检查了下一个字符。

关于c# - 当 UTC 与时区偏移一起使用时,DateTime.Parse 方法中是否存在错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65514261/

相关文章:

c# - CS0436 : Type conflicts with the imported type

php - 日期 toIsoString PHP

python - 将 TimedeltaIndex 转换为 DatetimeIndex

ruby-on-rails - Ruby 检查日期时间是否为 iso8601 并保存

c# - WPF 控件在窗口中的位置?

c# - LINQ 查询性能问题

r - 月日格式的日期对象

iso8601 - ISO8601 持续时间 'months' 和 'years' 有多少天?

azure - Azure 服务总线队列的 "Default message time to live"的值是多少?

c# - 排除特定上下文的正则表达式匹配