.NET Frameworkが提供する二つの日付操作用クラス、DateTimeとDateTimeOffsetの違いとそれらの使い分け方を解説する。
対象:.NET 3.5以降
DateTimeOffset構造体が導入された.NET Frameworkのバージョンは、正確には.NET Framework 3.5と同時にリリースされた.NET Framework 2.0 SP 1からである。しかし、MSDNには.NET Framework 3.5の新機能として記載されているので、本稿ではそれに従った。
DateTime構造体は.NET 1.0から利用可能。
日時処理のコーディングをしようとしたとき、現在の.NET Frameworkには利用できる構造体が2種類あって、どちらを使えばよいのか迷ってしまったことはないだろうか? .NET Frameworkの当初から利用できたDateTime構造体と、後から追加されたDateTimeOffset構造体である(いずれもSystem名前空間)。本稿では、その違いを解説する。
使い分けの目安は、時差を扱う必要があるかどうかである。扱う必要がなければ、使い慣れたDateTime構造体でよい。時差を取り扱わねばならないときは、DateTimeOffset構造体を使用する。
なおDateTime構造体には.NET Framework 2.0でKindプロパティが追加され、「時刻の種類」(=UTC/ローカル時刻/不明の3通り)を表現できるようになっている。本稿ではそれも紹介するが、複雑になるばかりなので、今となっては実際に使うことはないだろう。DateTimeOffset構造体を使えばよいからだ。
DateTimeOffset構造体を初期化するときには、必ず時差を指定する必要がある。
まず、DateTime構造体の初期化方法から見ていこう(次のコード)。通常は、日時だけを与える。「時刻の種類」を指定することもできるが、DateTimeOffset構造体を利用できるならばそちらを使った方がよい。
// 日時のみを指定
DateTime dt1 = new DateTime(2015, 6, 24, 5, 0, 0);
Console.WriteLine("DateTime(日時のみ指定): {0}, DateTime.Kind={1}", dt1, dt1.Kind);
// 出力結果:
// DateTime(日時のみ指定): 2015/06/24 5:00:00, DateTime.Kind=Unspecified
// DateTimeKind列挙体を使って時刻の種類を指定できる
// DateTimeKind.Local値はPCの現地時刻という意味
DateTime dt2 = new DateTime(2015, 6, 24, 5, 0, 0, DateTimeKind.Local);
Console.WriteLine("DateTime(Kind=Local): {0}, DateTime.Kind={1}", dt2, dt2.Kind);
// 出力結果:
// DateTime(Kind=Local): 2015/06/24 5:00:00, DateTime.Kind=Local
// DateTimeKind.Utc値は世界協定時という意味
DateTime dt3 = new DateTime(2015, 6, 23, 20, 0, 0, DateTimeKind.Utc);
Console.WriteLine("DateTime(Kind=UTC): {0}, DateTime.Kind={1}", dt3, dt3.Kind);
// 出力結果:
// DateTime(Kind=UTC): 2015/06/23 20:00:00, DateTime.Kind=Utc
// ただし、比較するときにDateTime.Kindプロパティの値は無視される
Console.WriteLine("2番目と3番目は等しいか?:{0}", dt2 == dt3);
// dt2とdt3は同一の時刻を表しているので(Localが日本標準時を示す場合)、
// 等しいという結果になってほしい
// 出力結果:
// 2番目と3番目は等しいか?:False
// 現在時刻は、現地時刻(Local)または世界協定時(UTC)で取得できる
DateTime dtLocalNow = DateTime.Now;
Console.WriteLine("DateTime.Now: {0}, DateTime.Kind={1}", dtLocalNow, dtLocalNow.Kind);
DateTime dtUtcNow = DateTime.UtcNow;
Console.WriteLine("DateTime.UtcNow: {0}, DateTime.Kind={1}", dtUtcNow, dtUtcNow.Kind);
// 出力例:
// DateTime.Now: 2015/06/24 11:05:27, DateTime.Kind=Local
// DateTime.UtcNow: 2015/06/24 2:05:27, DateTime.Kind=Utc
' 日時のみを指定
Dim dt1 As DateTime = New DateTime(2015, 6, 24, 5, 0, 0)
Console.WriteLine("DateTime(日時のみ指定): {0}, DateTime.Kind={1}", dt1, dt1.Kind)
' 出力結果:
' DateTime(日時のみ指定): 2015/06/24 5:00:00, DateTime.Kind=Unspecified
' DateTimeKind列挙体を使って時刻の種類を指定できる
' DateTimeKind.Local値はPCの現地時刻という意味
Dim dt2 As DateTime = New DateTime(2015, 6, 24, 5, 0, 0, DateTimeKind.Local)
Console.WriteLine("DateTime(Kind=Local): {0}, DateTime.Kind={1}", dt2, dt2.Kind)
' 出力結果:
' DateTime(Kind=Local): 2015/06/24 5:00:00, DateTime.Kind=Local
' DateTimeKind.Utc値は世界協定時という意味
Dim dt3 As DateTime = New DateTime(2015, 6, 23, 20, 0, 0, DateTimeKind.Utc)
Console.WriteLine("DateTime(Kind=UTC): {0}, DateTime.Kind={1}", dt3, dt3.Kind)
' 出力結果:
' DateTime(Kind=UTC): 2015/06/23 20:00:00, DateTime.Kind=Utc
' ただし、比較するときにDateTime.Kindプロパティの値は無視される
Console.WriteLine("2番目と3番目は等しいか?:{0}", dt2 = dt3)
' dt2とdt3は同一の時刻を表しているので(Localが日本標準時を示す場合)、
' 等しいという結果になってほしい
' 出力結果:
' 2番目と3番目は等しいか?:False
' 現在時刻は、現地時刻(Local)または世界協定時(UTC)で取得できる
Dim dtLocalNow As DateTime = DateTime.Now
Console.WriteLine("DateTime.Now: {0}, DateTime.Kind={1}", dtLocalNow, dtLocalNow.Kind)
Dim dtUtcNow As DateTime = DateTime.UtcNow
Console.WriteLine("DateTime.UtcNow: {0}, DateTime.Kind={1}", dtUtcNow, dtUtcNow.Kind)
' 出力例:
' DateTime.Now: 2015/06/24 11:41:00, DateTime.Kind=Local
' DateTime.UtcNow: 2015/06/24 2:41:00, DateTime.Kind=Utc
次に、DateTimeOffset構造体を初期化する方法である(次のコード)。前述したように、必ず時差も指定する必要がある。DateTime構造体を与えて初期化してもよい(その場合はDateTime構造体のKindプロパティから時差が決定される)。
// 日時と時差を指定
DateTimeOffset dto0 = new DateTimeOffset(2015, 6, 24, 5, 0, 0, TimeSpan.FromHours(9.0));
Console.WriteLine("DateTimeOffset(日時と時差を指定): {0}, DateTime.Kind={1}",
dto0, dto0.DateTime.Kind);
// 出力結果:
// DateTimeOffset(日時と時差を指定): 2015/06/24 5:00:00 +09:00, DateTime.Kind=Unspecified
// DateTime構造体を指定(Kind=Unspecified)
DateTimeOffset dto1 = new DateTimeOffset(dt1); // dt1は前述のコードを参照
Console.WriteLine("DateTimeOffset(Kind=UnspecifiedのDateTimeから): {0}, DateTime.Kind={1}",
dto1, dto1.DateTime.Kind);
// 出力結果:
// DateTimeOffset(Kind=UnspecifiedのDateTimeから): 2015/06/24 5:00:00 +09:00, DateTime.Kind=Unspecified
// DateTime構造体を指定(Kind=Local)
DateTimeOffset dto2 = new DateTimeOffset(dt2); // dt2は前述のコードを参照
Console.WriteLine("DateTimeOffset(Kind=LocalのDateTimeから): {0}, DateTime.Kind={1}",
dto2, dto2.DateTime.Kind);
// 出力結果:
// DateTimeOffset(Kind=LocalのDateTimeから): 2015/06/24 5:00:00 +09:00, DateTime.Kind=Unspecified
// DateTime構造体を指定(Kind=UTC)
DateTimeOffset dto3 = new DateTimeOffset(dt3); // dt3は前述のコードを参照
Console.WriteLine("DateTimeOffset(Kind=UTCのDateTimeから): {0}, DateTime.Kind={1}",
dto3, dto3.DateTime.Kind);
// 出力結果:
// DateTimeOffset(Kind=UTCのDateTimeから): 2015/06/23 20:00:00 +00:00, DateTime.Kind=Unspecified
// 比較するときに時差が考慮される
Console.WriteLine("2番目と3番目は等しいか?:{0}", dto2 == dto3);
// dto2とdto3は同一の時刻を表しているので(Localが日本標準時を示す場合)、
// 等しいという結果になってほしい
// 出力結果:
// 2番目と3番目は等しいか?:True
// 現在時刻は、現地時刻(Local)または世界協定時(UTC)で取得できる
DateTimeOffset dtoLocalNow = DateTimeOffset.Now;
Console.WriteLine("DateTimeOffset.Now: {0}, DateTime.Kind={1}",
dtoLocalNow, dtoLocalNow.DateTime.Kind);
DateTimeOffset dtoUtcNow = DateTimeOffset.UtcNow;
Console.WriteLine("DateTimeOffset.UtcNow: {0}, DateTime.Kind={1}",
dtoUtcNow, dtoUtcNow.DateTime.Kind);
// 出力例:
// DateTimeOffset.Now: 2015/06/24 11:17:31 +09:00, DateTime.Kind=Unspecified
// DateTimeOffset.UtcNow: 2015/06/24 2:17:31 +00:00, DateTime.Kind=Unspecified
' 日時と時差を指定
Dim dto0 As DateTimeOffset = New DateTimeOffset(2015, 6, 24, 5, 0, 0, TimeSpan.FromHours(9.0))
Console.WriteLine("DateTimeOffset(日時と時差を指定): {0}, DateTime.Kind={1}",
dto0, dto0.DateTime.Kind)
' 出力結果:
' DateTimeOffset(日時と時差を指定): 2015/06/24 5:00:00 +09:00, DateTime.Kind=Unspecified
' DateTime構造体を指定(Kind=Unspecified)
Dim dto1 As DateTimeOffset = New DateTimeOffset(dt1) ' dt1は前述のコードを参照
Console.WriteLine("DateTimeOffset(Kind=UnspecifiedのDateTimeから): {0}, DateTime.Kind={1}",
dto1, dto1.DateTime.Kind)
' 出力結果:
' DateTimeOffset(Kind=UnspecifiedのDateTimeから): 2015/06/24 5:00:00 +09:00, DateTime.Kind=Unspecified
' DateTime構造体を指定(Kind=Local)
Dim dto2 As DateTimeOffset = New DateTimeOffset(dt2) ' dt2は前述のコードを参照
Console.WriteLine("DateTimeOffset(Kind=LocalのDateTimeから): {0}, DateTime.Kind={1}",
dto2, dto2.DateTime.Kind)
' 出力結果:
' DateTimeOffset(Kind=LocalのDateTimeから): 2015/06/24 5:00:00 +09:00, DateTime.Kind=Unspecified
' DateTime構造体を指定(Kind=UTC)
Dim dto3 As DateTimeOffset = New DateTimeOffset(dt3) ' dt3は前述のコードを参照
Console.WriteLine("DateTimeOffset(Kind=UTCのDateTimeから): {0}, DateTime.Kind={1}",
dto3, dto3.DateTime.Kind)
' 出力結果:
' DateTimeOffset(Kind=UTCのDateTimeから): 2015/06/23 20:00:00 +00:00, DateTime.Kind=Unspecified
' 比較するときに時差が考慮される
Console.WriteLine("2番目と3番目は等しいか?:{0}", dto2 = dto3)
' dto2とdto3は同一の時刻を表しているので(Localが日本標準時を示す場合)、
' 等しいという結果になってほしい
' 出力結果:
' 2番目と3番目は等しいか?:True
' 現在時刻は、現地時刻(Local)または世界協定時(UTC)で取得できる
Dim dtoLocalNow As DateTimeOffset = DateTimeOffset.Now
Console.WriteLine("DateTimeOffset.Now: {0}, DateTime.Kind={1}",
dtoLocalNow, dtoLocalNow.DateTime.Kind)
Dim dtoUtcNow As DateTimeOffset = DateTimeOffset.UtcNow
Console.WriteLine("DateTimeOffset.UtcNow: {0}, DateTime.Kind={1}",
dtoUtcNow, dtoUtcNow.DateTime.Kind)
' 出力例:
' DateTimeOffset.Now: 2015/06/24 11:41:00 +09:00, DateTime.Kind=Unspecified
' DateTimeOffset.UtcNow: 2015/06/24 2:41:00 +00:00, DateTime.Kind=Unspecified
書式指定文字列を使って文字列に変換する際に、時差を入れ込むこともできる。
まず、DateTime構造体では、時差の書式指定文字として「K」を使う(次のコード)。DateTime構造体のKindプロパティが「Local」のときは、実行中のPCに設定されている時差が使われる。「Utc」のときは、世界協定時を表す文字「Z」になる。そして、「Unspecified」のときは何も出力されない。
// 日時のみを指定
DateTime dt1 = new DateTime(2015, 6, 24, 5, 0, 0);
Console.WriteLine("DateTime(日時のみ指定):{0:yyyy/M/d H:mm:ssK}", dt1);
// 出力結果:
// DateTime(日時のみ指定):2015/6/24 5:00:00
// DateTimeKind.LocalはPCの現地時刻を表す
DateTime dt2 = new DateTime(2015, 6, 24, 5, 0, 0, DateTimeKind.Local);
Console.WriteLine("DateTime(Kind=Local):{0:yyyy/M/d H:mm:ssK}", dt2);
// 出力結果:
// DateTime(Kind=Local):2015/6/24 5:00:00+09:00
// DateTimeKind.Utcは世界協定時を表す
DateTime dt3 = new DateTime(2015, 6, 23, 20, 0, 0, DateTimeKind.Utc);
Console.WriteLine("DateTime(Kind=UTC):{0:yyyy/M/d H:mm:ssK}", dt3);
// 出力結果:
// DateTime(Kind=UTC):2015/6/23 20:00:00Z
' 日時のみを指定
Dim dt1 As DateTime = New DateTime(2015, 6, 24, 5, 0, 0)
Console.WriteLine("DateTime(日時のみ指定):{0:yyyy/M/d H:mm:ssK}", dt1)
' 出力結果:
' DateTime(日時のみ指定):2015/6/24 5:00:00
' DateTimeKind.LocalはPCの現地時刻を表す
Dim dt2 As DateTime = New DateTime(2015, 6, 24, 5, 0, 0, DateTimeKind.Local)
Console.WriteLine("DateTime(Kind=Local):{0:yyyy/M/d H:mm:ssK}", dt2)
' 出力結果:
' DateTime(Kind=Local):2015/6/24 5:00:00+09:00
' DateTimeKind.Utcは世界協定時を表す
Dim dt3 As DateTime = New DateTime(2015, 6, 23, 20, 0, 0, DateTimeKind.Utc)
Console.WriteLine("DateTime(Kind=UTC):{0:yyyy/M/d H:mm:ssK}", dt3)
' 出力結果:
' DateTime(Kind=UTC):2015/6/23 20:00:00Z
次に、DateTimeOffset構造体の場合であるが、書式指定文字として「K」または「zzz」を使う(次のコード)。DateTime構造体とは異なり、常に時差が出力される。
DateTimeOffset dto1 = new DateTimeOffset(2015, 6, 24, 5, 0, 0, TimeSpan.FromHours(9.0));
Console.WriteLine("DateTimeOffset(時差+9時間):{0:yyyy/M/d H:mm:ss K}", dto1);
Console.WriteLine("DateTimeOffset(時差+9時間):{0:yyyy/M/d H:mm:ss zzz}", dto1);
// 出力結果:
// DateTimeOffset(時差+9時間):2015/6/24 5:00:00 +09:00
// DateTimeOffset(時差+9時間):2015/6/24 5:00:00 +09:00
DateTimeOffset dto2 = new DateTimeOffset(2015, 6, 24, 5, 0, 0, TimeSpan.FromHours(0.0));
Console.WriteLine("DateTimeOffset(時差0):{0:yyyy/M/d H:mm:ss K}", dto2);
Console.WriteLine("DateTimeOffset(時差0):{0:yyyy/M/d H:mm:ss zzz}", dto2);
// 出力結果:
// DateTimeOffset(時差0):2015/6/24 5:00:00 +00:00
// DateTimeOffset(時差0):2015/6/24 5:00:00 +00:00
DateTimeOffset dto3 = new DateTimeOffset(2015, 6, 24, 5, 0, 0, TimeSpan.FromHours(-7.0));
Console.WriteLine("DateTimeOffset(時差-7時間):{0:yyyy/M/d H:mm:ss K}", dto3);
Console.WriteLine("DateTimeOffset(時差-7時間):{0:yyyy/M/d H:mm:ss zzz}", dto3);
// 出力結果:
// DateTimeOffset(時差-7時間):2015/6/24 5:00:00 -07:00
// DateTimeOffset(時差-7時間):2015/6/24 5:00:00 -07:00
Dim dto1 As DateTimeOffset = New DateTimeOffset(2015, 6, 24, 5, 0, 0, TimeSpan.FromHours(9.0))
Console.WriteLine("DateTimeOffset(時差+9時間):{0:yyyy/M/d H:mm:ss K}", dto1)
Console.WriteLine("DateTimeOffset(時差+9時間):{0:yyyy/M/d H:mm:ss zzz}", dto1)
' 出力結果:
' DateTimeOffset(時差+9時間):2015/6/24 5:00:00 +09:00
' DateTimeOffset(時差+9時間):2015/6/24 5:00:00 +09:00
Dim dto2 As DateTimeOffset = New DateTimeOffset(2015, 6, 24, 5, 0, 0, TimeSpan.FromHours(0.0))
Console.WriteLine("DateTimeOffset(時差0):{0:yyyy/M/d H:mm:ss K}", dto2)
Console.WriteLine("DateTimeOffset(時差0):{0:yyyy/M/d H:mm:ss zzz}", dto2)
' 出力結果:
' DateTimeOffset(時差0):2015/6/24 5:00:00 +00:00
' DateTimeOffset(時差0):2015/6/24 5:00:00 +00:00
Dim dto3 As DateTimeOffset = New DateTimeOffset(2015, 6, 24, 5, 0, 0, TimeSpan.FromHours(-7.0))
Console.WriteLine("DateTimeOffset(時差-7時間):{0:yyyy/M/d H:mm:ss K}", dto3)
Console.WriteLine("DateTimeOffset(時差-7時間):{0:yyyy/M/d H:mm:ss zzz}", dto3)
' 出力結果:
' DateTimeOffset(時差-7時間):2015/6/24 5:00:00 -07:00
' DateTimeOffset(時差-7時間):2015/6/24 5:00:00 -07:00
日時を文字列として表示するとき、多くは時差を付けずに現地時刻とするだろう。DateTime構造体は時差を持っていないので、そのまま表示すればよい(Kindプロパティを利用しているときはToLocalTimeメソッドを使う)。
DateTimeOffset構造体では、ToLocalTimeメソッドを使って現地時刻に変換してから表示するのが基本になる(次のコード)。
DateTimeOffset dto1 = new DateTimeOffset(2015, 6, 24, 17, 0, 0, 0, TimeSpan.FromHours(9.0));
Console.WriteLine("dto1:{0}= {1:yyyy/M/d H:mm:ss}(現地時刻)", dto1, dto1.ToLocalTime());
// 出力結果:
// dto1:2015/06/24 17:00:00 +09:00= 2015/6/24 17:00:00(現地時刻)
DateTimeOffset dto2 = new DateTimeOffset(2015, 6, 24, 11, 0, 0, 0, TimeSpan.FromHours(-7.0));
Console.WriteLine("dto2:{0}= {1:yyyy/M/d H:mm:ss}(現地時刻)", dto2, dto2.ToLocalTime());
// 出力結果:
// dto2:2015/06/24 11:00:00 -07:00= 2015/6/25 3:00:00(現地時刻)
Dim dto1 As DateTimeOffset = New DateTimeOffset(2015, 6, 24, 17, 0, 0, 0, TimeSpan.FromHours(9.0))
Console.WriteLine("dto1:{0}= {1:yyyy/M/d H:mm:ss}(現地時刻)", dto1, dto1.ToLocalTime())
' 出力結果:
' dto1:2015/06/24 17:00:00 +09:00= 2015/6/24 17:00:00(現地時刻)
Dim dto2 As DateTimeOffset = New DateTimeOffset(2015, 6, 24, 11, 0, 0, 0, TimeSpan.FromHours(-7.0))
Console.WriteLine("dto2:{0}= {1:yyyy/M/d H:mm:ss}(現地時刻)", dto2, dto2.ToLocalTime())
' 出力結果:
' dto2:2015/06/24 11:00:00 -07:00= 2015/6/25 3:00:00(現地時刻)
それぞれの構造体のParse/ParseExact/TryParse/TryParseExactメソッドを使えばよい。ここでは、TryParseメソッドを使う例を紹介しよう。
まずDateTime構造体であるが、現地時刻に変換される(次のコード)。文字列にあった時差情報は失われるのである。
DateTime dt = new DateTime();
// 時差の文字列なし
string s0 = "Wed, 24 Jun 2015 05:00:00";
DateTime.TryParse(s0, out dt);
Console.WriteLine("DateTime.TryParse:{0} ({1})", dt, dt.Kind);
// 出力結果:
// DateTime.TryParse:2015/06/24 5:00:00 (Unspecified)
// 現地時刻と等しい時差
string s1 = "Wed, 24 Jun 2015 05:00:00 +9:00";
DateTime.TryParse(s1, out dt);
Console.WriteLine("DateTime.TryParse:{0} ({1})", dt, dt.Kind);
// 出力結果:
// DateTime.TryParse:2015/06/24 5:00:00 (Local)
// 時差−2時間
string s2 = "Tue, 23 Jun 2015 18:00:00 -2:00";
DateTime.TryParse(s2, out dt);
Console.WriteLine("DateTime.TryParse:{0} ({1})", dt, dt.Kind);
// 出力結果:
// DateTime.TryParse:2015/06/24 5:00:00 (Local)
// 時差0(特別に「GMT」や「Z」を認識する)
string s3 = "Tue, 23 Jun 2015 20:00:00 GMT";
DateTime.TryParse(s3, out dt);
Console.WriteLine("DateTime.TryParse:{0} ({1})", dt, dt.Kind);
// 出力結果:
// DateTime.TryParse:2015/06/24 5:00:00 (Local)
Dim dt As DateTime = New DateTime()
' 時差の文字列なし
Dim s0 As String = "Wed, 24 Jun 2015 05:00:00"
DateTime.TryParse(s0, dt)
Console.WriteLine("DateTime.TryParse:{0} ({1})", dt, dt.Kind)
' 出力結果:
' DateTime.TryParse:2015/06/24 5:00:00 (Unspecified)
' 現地時刻と等しい時差
Dim s1 As String = "Wed, 24 Jun 2015 05:00:00 +9:00"
DateTime.TryParse(s1, dt)
Console.WriteLine("DateTime.TryParse:{0} ({1})", dt, dt.Kind)
' 出力結果:
' DateTime.TryParse:2015/06/24 5:00:00 (Local)
' 時差−2時間
Dim s2 As String = "Tue, 23 Jun 2015 18:00:00 -2:00"
DateTime.TryParse(s2, dt)
Console.WriteLine("DateTime.TryParse:{0} ({1})", dt, dt.Kind)
' 出力結果:
' DateTime.TryParse:2015/06/24 5:00:00 (Local)
' 時差0(特別に「GMT」や「Z」を認識する)
Dim s3 As String = "Tue, 23 Jun 2015 20:00:00 GMT"
DateTime.TryParse(s3, dt)
Console.WriteLine("DateTime.TryParse:{0} ({1})", dt, dt.Kind)
' 出力結果:
' DateTime.TryParse:2015/06/24 5:00:00 (Local)
DateTimeOffset構造体では、文字列中の時差をそのまま保持する(次のコード)。文字列中に時差が書かれていないときは、現地時刻と解釈される。
DateTimeOffset dto = new DateTimeOffset();
// 時差の文字列なし(=現地時刻として解釈される)
string s0 = "Wed, 24 Jun 2015 05:00:00";
DateTimeOffset.TryParse(s0, out dto);
Console.WriteLine("DateTimeOffset.TryParse:{0}", dto);
// 出力結果:
// DateTimeOffset.TryParse:2015/06/24 5:00:00 +09:00
// 現地時刻と等しい時差
string s1 = "Wed, 24 Jun 2015 05:00:00 +9:00";
DateTimeOffset.TryParse(s1, out dto);
Console.WriteLine("DateTimeOffset.TryParse:{0}", dto);
// 出力結果:
// DateTimeOffset.TryParse:2015/06/24 5:00:00 +09:00
// 時差−2時間
string s2 = "Tue, 23 Jun 2015 18:00:00 -2:00";
DateTimeOffset.TryParse(s2, out dto);
Console.WriteLine("DateTimeOffset.TryParse:{0}", dto);
// 出力結果:
// DateTimeOffset.TryParse:2015/06/23 18:00:00 -02:00
// 時差0(特別に「GMT」や「Z」を認識する)
string s3 = "Tue, 23 Jun 2015 20:00:00 GMT";
DateTimeOffset.TryParse(s3, out dto);
Console.WriteLine("DateTimeOffset.TryParse:{0}", dto);
// 出力結果:
// DateTimeOffset.TryParse:2015/06/23 20:00:00 +00:00
Dim dto As DateTimeOffset = New DateTimeOffset()
' 時差の文字列なし(=現地時刻として解釈される)
Dim s0 As String = "Wed, 24 Jun 2015 05:00:00"
DateTimeOffset.TryParse(s0, dto)
Console.WriteLine("DateTimeOffset.TryParse:{0}", dto)
' 出力結果:
' DateTimeOffset.TryParse:2015/06/24 5:00:00 +09:00
' 現地時刻と等しい時差
Dim s1 As String = "Wed, 24 Jun 2015 05:00:00 +9:00"
DateTimeOffset.TryParse(s1, dto)
Console.WriteLine("DateTimeOffset.TryParse:{0}", dto)
' 出力結果:
' DateTimeOffset.TryParse:2015/06/24 5:00:00 +09:00
' 時差−2時間
Dim s2 As String = "Tue, 23 Jun 2015 18:00:00 -2:00"
DateTimeOffset.TryParse(s2, dto)
Console.WriteLine("DateTimeOffset.TryParse:{0}", dto)
' 出力結果:
' DateTimeOffset.TryParse:2015/06/23 18:00:00 -02:00
' 時差0(特別に「GMT」や「Z」を認識する)
Dim s3 As String = "Tue, 23 Jun 2015 20:00:00 GMT"
DateTimeOffset.TryParse(s3, dto)
Console.WriteLine("DateTimeOffset.TryParse:{0}", dto)
' 出力結果:
' DateTimeOffset.TryParse:2015/06/23 20:00:00 +00:00
最後に、時差が異なる二つの日時の間の時間を求めてみよう。日時の引き算である。
DateTime構造体では、単純に引き算をしてもうまくいかない。別に時差データを持っておかねばならないのだ(次のコード)。
// 例:飛行機の飛行時間
// 成田17:00発、ロサンゼルス同日11:00着(夏時間、UTC-7)
// DateTimeでは、単純に引き算をしてはダメ
DateTime dtDep = new DateTime(2015, 6, 24, 17, 0, 0, 0); // 17:00発
DateTime dtArr = new DateTime(2015, 6, 24, 11, 0, 0, 0); // 同日11:00着
TimeSpan dtFlightTime = dtArr.Subtract(dtDep);
Console.WriteLine("飛行時間は{0}時間(単純な引き算)", dtFlightTime.Hours);
// 出力結果:
// 飛行時間は−6時間(単純な引き算)
// 別の手段で保持しておいた時差を使ってUTCに変換してから引き算をする
DateTime dtDepUtc = dtDep.AddHours(-9.0);
DateTime dtArrUtc = dtArr.AddHours(+7.0);
TimeSpan dtFlightTimeUtc = dtArrUtc.Subtract(dtDepUtc);
Console.WriteLine("飛行時間は{0}時間(UTC換算後)", dtFlightTimeUtc.Hours);
// 出力結果:
// 飛行時間は10時間(UTC換算後)
' 例:飛行機の飛行時間
' 成田17:00発、ロサンゼルス同日11:00着(夏時間、UTC-7)
' DateTimeでは、単純に引き算をしてはダメ
Dim dtDep As DateTime = New DateTime(2015, 6, 24, 17, 0, 0, 0)
Dim dtArr As DateTime = New DateTime(2015, 6, 24, 11, 0, 0, 0)
Dim dtFlightTime As TimeSpan = dtArr.Subtract(dtDep)
Console.WriteLine("飛行時間は{0}時間(単純な引き算)", dtFlightTime.Hours)
' 出力結果:
' 飛行時間は−6時間(単純な引き算)
' 別の手段で保持しておいた時差を使ってUTCに変換してから引き算をする
Dim dtDepUtc As DateTime = dtDep.AddHours(-9.0)
Dim dtArrUtc As DateTime = dtArr.AddHours(+7.0)
Dim dtFlightTimeUtc As TimeSpan = dtArrUtc.Subtract(dtDepUtc)
Console.WriteLine("飛行時間は{0}時間(UTC換算後)", dtFlightTimeUtc.Hours)
' 出力結果:
' 飛行時間は10時間(UTC換算後)
DateTimeOffset構造体では、単に引き算をすればよい(次のコード)。
// 例:飛行機の飛行時間
// 成田17:00発、ロサンゼルス同日11:00着(夏時間、UTC-7)
DateTimeOffset dtoDep = new DateTimeOffset(2015, 6, 24, 17, 0, 0, 0,
TimeSpan.FromHours(9.0));
DateTimeOffset dtoArr = new DateTimeOffset(2015, 6, 24, 11, 0, 0, 0,
TimeSpan.FromHours(-7.0));
TimeSpan dtoFlightTime = dtoArr.Subtract(dtoDep);
Console.WriteLine("飛行時間は{0}時間", dtoFlightTime.Hours);
// 出力結果:
// 飛行時間は10時間
' 例:飛行機の飛行時間
' 成田17:00発、ロサンゼルス同日11:00着(夏時間、UTC-7)
Dim dtoDep As DateTimeOffset = New DateTimeOffset(2015, 6, 24, 17, 0, 0, 0,
TimeSpan.FromHours(9.0))
Dim dtoArr As DateTimeOffset = New DateTimeOffset(2015, 6, 24, 11, 0, 0, 0,
TimeSpan.FromHours(-7.0))
Dim dtoFlightTime As TimeSpan = dtoArr.Subtract(dtoDep)
Console.WriteLine("飛行時間は{0}時間", dtoFlightTime.Hours)
' 出力結果:
' 飛行時間は10時間
.NET Framework 3.5以降を使っているとき、時差に関わる処理がある/ありそうならば、迷わずDateTimeOffset構造体を使っていただきたい。そしてDateTime構造体のKindプロパティのことは忘れてほしい。DateTimeKindに関する話を飛ばして本稿を読み直してもらえば、DateTimeKindによってどれだけ話が複雑になっているか分かるだろう。
なお、夏時間を扱いたいときは、TimeZoneInfoクラスを使用する。そのコード例は「WinRT/Metro TIPS:夏時間を考慮して日時を変換するには?[Win 8/WP 8]」をご覧いただきたい。
利用可能バージョン: .NET Framework 3.5以降
カテゴリ: クラスライブラリ 処理対象:日付と時刻
使用ライブラリ: DateTime構造体(System名前空間)
使用ライブラリ: DateTimeOffset構造体(System名前空間)
使用ライブラリ: TimeSpan構造体(System名前空間)
関連TIPS: 日時や時間間隔の加減算を行うには?
関連TIPS: UTC(世界協定時)を取得するには?[C#、VB]
関連TIPS: 日付や時刻を文字列に変換するには?
関連TIPS: 日付や時刻の文字列をDateTimeオブジェクトに変換するには?
Copyright© Digital Advantage Corp. All Rights Reserved.