JSON文字列をローカルタイムゾーンの.NETDateTimeに逆シリアル化すると、2時間が追加されます

Nov 27 2020

ローカルPCでこのjson文字列 "2020-10-05T07:29:00 + 00:00"をDateTimeオブジェクトに逆シリアル化すると、最終的に2020-10-05 09:29になり、07:29になります。日付はローカル(+00:00)として指定されているため、余分な2時間がどこから来ているのかわかりません。この質問の日時タイムゾーンの逆シリアル化を調べてみましたが、.ToLocalTime()を使用して日付を変換しても何も起こりません。

コンテキストは、多くの日時を持つ外部APIからの空港を含む大きなjson文字列であり、UTCのものもあれば、現地時間のものもあります。正しい日時を生成する文字列を逆シリアル化する最も簡単な方法を見つける必要があります。

現地時間は世界中のどこにでもある可能性があるため、アプリケーションを実行するサーバーに依存しないようにする必要があることに注意してください。

NewtonSoft.Jsonを使用して逆シリアル化するコード例を次に示します。

static void Main(string[] args)
    {
        var json =
            "{\"UTC\": \"2020-10-05T05:29:00Z\",\"Local\": \"2020-10-05T07:29:00+00:00\" }";
        var expected = new DateTime(2020,10,5,7,29,0);
        var foo = JsonConvert.DeserializeObject<CustomTime>(json);
        Console.WriteLine($"UTC:{foo.UTC} ({foo.UTC.Kind}).\r\nLOC:{foo.Local} ({foo.Local.Kind})");
        System.Console.WriteLine(foo.Local.Equals(expected) ? "All good" : "Conversion failed");
    }

public sealed class CustomTime
{
    public DateTime UTC { get; set; }
    public DateTime Local { get; set; }
}

これは私のタイムゾーン(UTC +2 DaylightSavingTime)での私の出力です:

UTC:05-10-2020 05:29:00(UTC)。LOC:05-10-2020 09:29:00(ローカル)変換に失敗しました

これがドットネットフィドルです https://dotnetfiddle.net/uHLdAh サーバーはおそらくGMTを実行しているため、これにより正しい出力が生成されます。

回答

1 iikkoo Nov 27 2020 at 14:56

問題は、「2020-10-05T07:29:00 + 00:00」が現地時間ではなく、0時間オフセットのUTC時間として解釈されることです。また、マシンで実行すると、現在のタイムゾーンのオフセット、つまり+02:00hが追加されます。

たとえば、現在の時刻は08:36で、私のタイムゾーンはCETです。UTCでDateTimeOffsetオブジェクトを作成すると、2020-11-27T06:36:00 + 02:00と表示されます。

したがって、次のコードを実行すると、実行中のマシンのタイムゾーンに応じて異なる結果が得られます。

 // Current time
 dto = DateTimeOffset.Now;
 Console.WriteLine(dto.LocalDateTime);
 // UTC time
 dto = DateTimeOffset.UtcNow;
 Console.WriteLine(dto.LocalDateTime);

dotnetfiddle.netで実行した場合の出力:

3/11/2007 10:30:00 AM
3/11/2007 9:30:00 AM

ローカルマシンで実行した場合の出力:

2020-11-27 08:54:09
2020-11-27 08:54:09

入力がUTC時間で適切なオフセット0で与えられているのか、それとも「ローカル」時間でオフセットに誤りがあるのか​​を判断する必要があります。次に、新しい日時オブジェクトに必要なタイムゾーンを指定するDateTimeOffsetオブジェクトを作成する必要があります。

var dto = new DateTimeOffset(2020,10,5,7,29,0, new TimeSpan(2, 0, 0));
Console.WriteLine(dto);
Console.WriteLine(dto.LocalDateTime.Kind);
Console.WriteLine(dto.UtcDateTime);
Console.WriteLine(dto.UtcDateTime.Kind);

これにより、次の出力が得られます。

2020-10-05 07:29:00 +02:00
Local
2020-10-05 05:29:00
Utc

これで、DateTimeOffsetオブジェクトが期待どおりに動作するようになりました。

MRaymaker Nov 27 2020 at 19:41

問題の解決策は単純なものであることが証明されました。すべての時間がUTCであると仮定してください。これにより、変換のすべての問題が修正されます。

var foo = JsonConvert.DeserializeObject<CustomTime>(json, new JsonSerializerSettings
{
   DateTimeZoneHandling = DateTimeZoneHandling.Utc
});