C#中的DateTime.ToString带有zzz在dotnet framework中出现问题,但在dotnet core中没有问题。

4

我写作时使用的本地时间是GMT+01:00。当我按照以下方式进行ToString操作时,我经历了一些出乎意料的事情。来看看:

演示本地系统设置带有+01:00时区(所有这些都运行正常):

var myLocalDate = new DateTime(2020, 11, 25, 08, 00, 00, DateTimeKind.Local);
Assert.AreEqual("2020-11-25T08:00:00+01:00", myLocalDate.ToString(@"yyyy-MM-dd\THH:mm:sszzz"));
Assert.AreEqual(DateTimeKind.Local, myLocalDate.Kind);
Assert.AreEqual(myLocalDate, myLocalDate.ToLocalTime());

现在我手动减去一个小时并指定“utc”时区,创建了同样的时间(UTC时间)。 但是当我调用ToString时,时区被写成+01:00,我原本希望它是+00:00:

var myUtcDate = new DateTime(2020, 11, 25, 07, 00, 00, DateTimeKind.Utc);
// THIS Breaks:
Assert.AreEqual("2020-11-25T07:00:00+00:00", myUtcDate.ToString(@"yyyy-MM-dd\THH:mm:sszzz"));

错误信息:

消息: Assert.AreEqual失败。 期望值:<2020-11-25T07:00:00+00:00>。 实际值:<2020-11-25T07:00:00+01:00>。

这里是关于日期时间和格式方面的疑问,还是说这可能是一个已知的 bug?

我正在运行 .Net Framework 4.8

这篇文章也是关于同样问题的:如何解决DateTimeInvalidLocalFormat错误:"正在将UTC DateTime转换为仅适用于本地时间的格式文本"?

更新:

按照以下程序运行会在dotnet framework和dotnet core中产生不同的结果(正如evk所提到的):

Console.WriteLine(new DateTime(2025, 11, 25, 07, 00, 00, DateTimeKind.Utc).ToString(@"yyyy-MM-dd\THH:mm:sszzz"));

dotnet core输出:

2020-11-25T07:00:00+00:00

dotnet Framework输出:

2020-11-25T07:00:00+01:00

此外,当以调试模式运行dotnet框架时,将显示以下调试助手消息,但在DateTime.ToString()内部被忽略:

“Managed Debugging Assistant 'DateTimeInvalidLocalFormat' : '正在将UTC DateTime转换为文本格式,该格式仅对本地时间正确。调用DateTime.ToString使用“z”格式说明符可能会发生这种情况,该说明符将在输出中包括本地时区偏移量。在这种情况下,请改用指定UTC时间的“Z”格式说明符或使用“o”格式字符串,这是建议的将DateTime持久化为文本的方法。当传递DateTime以由XmlConvert或DataSet序列化时,这也会发生。如果使用XmlConvert.ToString,请传递XmlDateTimeSerializationMode.RoundtripKind以正确序列化。如果使用DataSet,请在DataColumn对象上设置DateTimeMode为DataSetDateTime.Utc。“


4
每当我问自己“这是框架或编译器中的 bug 吗?”答案总是100%的情况下都是“不是”。我相信你已经明白,但为了保险起见,请确认您是否需要进一步的翻译。 - Uwe Keim
1
@Seabizkit:我不清楚OP的情况,但我发现你的评论非常难以理解。你可能需要更清晰地重新写一下。 - Jon Skeet
1
@UweKeim: 个人而言,我会选择99.9%。编译器和框架肯定存在错误,但我总是更加怀疑我的代码。 - Jon Skeet
1
@Seabizkit:我非常了解日期/时间格式 - 我只是不理解你的评论。它非常不精确 - “移动[...]” - 移动到哪里?为什么?“检查您的比较值是否错误” - 您所说的“错误”是什么意思?“MM/dd/yyyy hh:mm:ss.fff格式有多有效” - 这不是OP正在使用的格式 - 没有遗漏点。OP并没有尝试获取亚秒值。zzz作为格式说明符是有效的,正如您链接到的页面中所记录的那样。我不知道您在评论中想表达什么,但我认为它不清楚,不正确或两者都有。 - Jon Skeet
2
一场比赛,西比修马并非命中注定要获胜,我感到担忧。 - Matt Evans
显示剩余4条评论
1个回答

7
不,它的行为符合文档。从关于zzz格式说明符的文档可以看出(强调我自己的):
DateTime值,"zzz"自定义格式说明符表示本地操作系统时区与UTC之间的带符号偏移量,以小时和分钟为单位。它不反映实例的DateTime.Kind属性的值。因此,"zzz"格式说明符不建议与DateTime值一起使用。
这可能是不幸的,但它不是一个 bug。
请注意,.NET Core(和.NET 5.0)显然没有按照文档的方式运行。虽然你可以争论它在.NET Core中被“修复”了,但我认为以一种未记录的方式运行是一个 bug,并且可能使代码迁移比预期更困难。
我建议你遵循文档中的建议,避免在DateTime值中使用zzz。我还建议您使用我的Noda Time库,其中不存在“一个值可能是本地时间,也可能是UTC”的歧义,但这略有不同。我不希望你在使用Noda Time时遇到这个问题,你的其他日期/时间代码也应更清晰。

有趣的是,在.NET 4.8中,从Visual Studio进行调试时,我第一次看到某种“调试助手”会在ToString上中断执行,并基本上告诉我你在这里写的内容(使用本地格式说明符转换UTC日期时间)。这不是异常(然后可以继续执行)。 - Evk
1
在.NET Core中,这个问题似乎已经被解决了,OP的测试也通过了。 - Evk
@jon 感谢您澄清这一点,我同意,这非常不幸。 - Stephan Møller
1
@StephanRyer:我个人会使用六月,因为我的机器处于英国时区...现在无论如何我都会看到00:00。 - Jon Skeet
1
@StephanRyer:但是没错,我已经复现了它。很奇怪。我会更新我的答案。 - Jon Skeet
显示剩余4条评论

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