Date型 (C# では Datetime 型) でタイムゾーンを意識する場合、注意が必要です。
まず Date 型は 3つのタイムゾーン(モード)を持っています。
- ローカル時 (.Kind = DateTimeKind.Local)
Dim d1 = Date.Now とした場合のモード。
OS の時計の表示と同じ。 - 世界標準時 (.Kind = DateTimeKind.Utc)
Dim d2 = Date.UtcNow とした場合のモード。
世界標準時として記憶する。タイムゾーンが JST の場合、OSの表示 -9 時間になる。 - 不定 (.Kind = DateTimeKind.Unspecified)
Dim d3 = Date.Parse("2013/7/1 12:00:00") のように「タイムゾーン」を指定しなかった場合のモード。
指定した時刻そのものを記憶する。
これらのモードを意識せずに扱った場合、様々な問題を引き起こす可能性があります。
たとえば以下のような問題が予想されます。
- 問題1:上記d1 と 上記d2 を差し引くと、-9:00 が算出される
コード
Dim d1 = Date.Now Dim d2 = Date.UtcNow Console.Writeline(d2 - d1)
結果
-9:00:00
- 問題2:タイムゾーンが不定な時刻を、世界標準時,ローカル時に変換した場合
コード
Dim a = Date.Parse("2013/7/6") Console.WriteLine(a) Console.WriteLine(a.ToUniversalTime) Console.WriteLine(a.ToLocalTime)
結果
2013/07/06 0:00:00 2013/07/05 15:00:00 ← 変換前時刻 -9:00 (変換前時刻が ローカル時 だとして計算) 2013/07/06 9:00:00 ← 変換前時刻 +9:00 (変換前時刻が 世界標準時 だとして計算)
- 問題3:タイムゾーンは比較の対象外
コード
Dim a = New Date(2013, 7, 6, 0, 0, 0, DateTimeKind.Local) Dim b = New Date(2013, 7, 6, 0, 0, 0, DateTimeKind.Utc) Dim c = New Date(2013, 7, 6, 0, 0, 0, DateTimeKind.Unspecified) Console.WriteLine(a = b) Console.WriteLine(a = c)
結果
True True
- 問題4:タイムゾーンなし文字列だと不定モードで評価され、タイムゾーンつき文字列だとローカル時に変換される
コード
Dim a = Date.Parse("2013/7/6") Dim b = Date.Parse("2013/7/6 +1:00") Console.WriteLine("{0} {1}", a, a.Kind.ToString) Console.WriteLine("{0} {1}", b, b.Kind.ToString)
結果
2013/07/06 0:00:00 Unspecified ← 不定モードで評価 2013/07/06 8:00:00 Local ← タイムゾーンを考慮の上、ローカル時に変換 (元のタイムゾーン情報は失われる)