带有 zzz 的 C# DateTime.ToString 在 dotnet 框架中中断,但不在 dotnet 核心中

Ste*_*yer 3 c# datetime

我的当地时间是格林威治标准时间 +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());
Run Code Online (Sandbox Code Playgroud)

现在我通过手动减去一个小时并将“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"));
Run Code Online (Sandbox Code Playgroud)

错误信息:

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

我是否在这里错过了有关日期时间和格式的信息,或者这可能是一个已知的错误?

我运行 .Net Framework 4.8

这篇文章是关于同样的问题,我看到:如何解决 DateTimeInvalidLocalFormat 错误:“UTC DateTime 正在转换为仅适用于当地时间的格式的文本。”?

更新:

运行以下程序会在 dotnet 框架和 dotnet 核心中产生不同的结果(如 evk 所述):

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

dotnet 核心打印:

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

dotnet 框架打印:

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

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

托管调试助手“DateTimeInvalidLocalFormat”:“UTC 日期时间正在转换为仅适用于当地时间的格式的文本。使用“z”格式说明符调用 DateTime.ToString 时可能会发生这种情况,该说明符将在输出中包含本地时区偏移量。在这种情况下,请使用指定 UTC 时间的“Z”格式说明符,或使用“o”格式字符串,这是在文本中保留 DateTime 的推荐方法。当传递要由 XmlConvert 或 DataSet 序列化的 DateTime 时,也会发生这种情况。如果使用 XmlConvert.ToString,请传入 XmlDateTimeSerializationMode.RoundtripKind 以正确序列化。如果使用 DataSet,请将 DataColumn 对象上的 DateTimeMode 设置为 DataSetDateTime.Utc。'

Jon*_*eet 5

不,它的行为与记录一致。从格式说明符文档zzz(强调我的):

对于DateTime值,“zzz”自定义格式说明符表示本地操作系统时区与 UTC 的有符号偏移量,以小时和分钟为单位。它不反映实例DateTime.Kind属性的值。因此,不建议将“zzz”格式说明符用于DateTime值。

可以说这是不幸的,但这不是一个错误。

请注意,.NET Core(和 .NET 5.0)显然不像文档那样表现。虽然您可能会争辩说它在 .NET Core 中是“固定的”,但我建议以未记录的方式行事本身就是一个错误,并且可能使代码迁移比预期的更难。

我建议您遵循文档中的建议,并避免使用zzzwith DateTimevalues。我建议改用我的Noda Time库,在“可能是本地的,或者可能是 UTC”的值方面没有歧义,但这是一个稍微不同的问题。(我不希望您使用 Noda Time 遇到这个问题,希望您的其他日期/时间代码更清晰。)