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 日期,末尾有一个无效的任意字符,它会错误地解析而不会出现错误,其中两个任意字符似乎正确失败。
似乎发生的事情如下
- 在
ParseISO8601
中解析时它在ParseTimeZone
中获取正确的时区信息-07:00
- 这使得
str
具有最后一个索引 1 - 然后它会检查
str.Match('#')
前缀会增加索引(我认为这是错误)。 - 此时,由于索引位于字符串末尾,因此在后续检查中假定解析已完成
比赛摘录
我的评论
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/