我们的C# DateTime类型出现这种行为的原因是什么?

5
[Test]
public void Sadness()
{
   var dateTime = DateTime.UtcNow;
   Assert.That(dateTime, Is.EqualTo(DateTime.Parse(dateTime.ToString())));
}

失败:

 Expected: 2011-10-31 06:12:44.000
 But was:  2011-10-31 06:12:44.350

我希望了解ToString()等方法背后导致此行为的原因。

编辑:在看到Jon的答案之后:

[Test]
public void NewSadness()
{
    var dateTime = DateTime.UtcNow;
    Assert.That(dateTime, Is.EqualTo(DateTime.Parse(dateTime.ToString("o"))));
}

结果:

Expected: 2011-10-31 12:03:04.161
But was:  2011-10-31 06:33:04.161

相同的结果使用大写和小写的'o'。我正在阅读文档,但仍然不清楚。

添加 CultureInfo.InvariantCulture 没有起到作用:它产生了 期望值:2011-10-31 12:09:51.928 但实际值是:2011-10-31 06:39:51.928 - Zasz
一些解析逻辑/转换为字符串的逻辑增加了6小时30分钟的时间:( - Zasz
2个回答

9
请看一下dateTime.ToString()的输出结果 - 它通常只能精确到秒,但这取决于文化设置。如果ToString()只提供了精确到秒的结果,那么解析该字符串就无法提供更多信息...。
您可以使用"o"标准格式字符串来提供一个可循环的字符串表示。例如,目前它会产生类似以下的东西:
2011-10-31T06:28:34.6425574Z

编辑:您需要使用相同的解析器才能获得相同的结果:

string text = dateTime.ToString("o");
// Culture is irrelevant when using the "o" specifier
DateTime parsed = DateTime.ParseExact(text, "o", null,
                                      DateTimeStyles.RoundtripKind);

1
+1. Zasz,请阅读Jon提供的MSDN文章,特别是关于“o”和“u”格式的部分。里面有详细的解释如何实现往返转换。 - Alexei Levenkov

6

默认的格式说明符是“G” - 通用格式 - 其准确性有限。如果您想要精确地复制同样的内容,请使用回路说明符“O”。

string s = dateTime.ToString("O", CultureInfo.InvariantCulture);
Assert.That(dateTime, Is.EqualTo(DateTime.ParseExact(
       s, "O", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind)));

我编辑了我的问题,加入了你的想法 - 结果很奇怪,我仍然感到困惑。 - Zasz
1
@Zasz,为什么结果很奇怪?如果在你的测试中“期望值”和“实际值”的位置颠倒了,这是否会增加混淆呢?这是我们所说的全部吗? - Marc Gravell
1
@Zasz 也可以尝试使用 DateTime.Parse(s, null, DateTimeStyles.RoundtripKind) - Marc Gravell
1
@Zasz 强调 - 重要的是确保解析器知道它正在期望往返。 - Marc Gravell
需要RoundtripKind是个好主意。我刚试了一下,确实需要它才能正确地往返转换。这相当奇怪,因为它在格式化的字符串中已经存在了。怪事。 - Jon Skeet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接