C#DateTime.ToString with zzzは、dotnetフレームワークでは壊れますが、dotnetcoreでは壊れません

Nov 25 2020

執筆時点として、グリニッジ標準時+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>。

ここで日時と形式について何か見逃しているのでしょうか、それともこれは既知のバグでしょうか?

.Net Framework4.8を実行しています

この投稿はほぼ同じ問題です。DateTimeInvalidLocalFormatエラーを解決する方法:「UTCDateTimeは、現地時間に対してのみ正しい形式のテキストに変換されています。」?

更新:

次のプログラムを実行すると、dotnetフレームワークとdotnetコアで異なる結果が得られます(evkで言及されています)。

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

dotnetコアプリント:

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

dotnetフレームワークの印刷:

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

さらに、dotnet Frameworkをデバッグモードで実行すると、次のデバッグアシスタントメッセージが表示されますが、DateTime.ToString()では内部的に無視されます。

Managed Debugging Assistant'DateTimeInvalidLocalFormat ':' UTC DateTimeは、現地時間に対してのみ正しい形式のテキストに変換されています。これは、「z」形式指定子を使用してDateTime.ToStringを呼び出すときに発生する可能性があります。これにより、出力にローカルタイムゾーンオフセットが含まれます。その場合は、UTC時刻を指定する「Z」形式指定子を使用するか、「o」形式の文字列を使用します。これは、DateTimeをテキストで保持するための推奨される方法です。これは、XmlConvertまたはDataSetによってシリアル化されるDateTimeを渡すときにも発生する可能性があります。XmlConvert.ToStringを使用している場合は、XmlDateTimeSerializationMode.RoundtripKindを渡して正しくシリアル化します。DataSetを使用する場合は、DataColumnオブジェクトのDateTimeModeをDataSetDateTime.Utcに設定します。'

回答

5 JonSkeet Nov 25 2020 at 19:09

いいえ、文書化されているとおりに動作しています。フォーマット指定子のドキュメントzzzから(私の強調):

DateTime値、「ZZZ」のカスタム書式指定子が署名した時間と分で測定されたUTCからローカルのオペレーティング・システムのタイムゾーンのオフセットを表します。インスタンスのDateTime.Kindプロパティの値は反映されません。このため、「zzz」形式指定子をDateTime値とともに使用することはお勧めしません。

間違いなくそれは残念ですが、バグではありません。

.NET Core(および.NET 5.0)、文書化されているように動作しないようです。.NET Coreでは「修正済み」であると主張することもできますが、文書化されていない方法で動作すること自体がバグであり、コードの移行が予想よりも難しくなる可能性があることをお勧めします。

ドキュメントの推奨事項に従い、値zzzとともに使用しないことをお勧めしDateTimeます。私は思い私の使用をお勧め野田時間値の面で曖昧さが存在しない場合、代わりにライブラリを「多分ローカルであること、または多分UTCであること」、それだ少し別の問題。(Noda Timeを使用してこの問題が発生することはないと思います。また、他の日付/時刻コードがより明確になることを願っています。)