DateTimeとDateTimeOffsetはどちらも日時を扱う方ですが、時刻の種類の扱いが異なります。 DateTimeでは時刻がローカル時刻とUTCのどちらを表すかという2種類で時刻の種類を扱うのに対し、DateTimeOffsetでは時刻のオフセット値を用いることでローカル時刻・UTCだけでなくその他の地域の時刻を扱うことができます。
ここでは時刻の種類の扱い方の違いや、時刻をローカル時刻・UTCに変換する方法、その際の注意点などについて見ていきます。 また、オフセット値だけでなくタイムゾーン情報を扱うTimeZoneInfoクラスについても見ていきます。
なお、本文中にあるいくつかのサンプルコードについて、実行環境に設定されているタイムゾーン・言語・書式等によって実行結果・出力内容が変わるものもが存在します。 特に明記していない場合は、日本標準時(UTC+9)・日本語の環境での実行結果となります。
時刻の種類・オフセット
DateTime.Kind
DateTimeには、時刻がローカル時刻とUTCのどちらを表すのかを判別するためのプロパティKindが用意されています。
DateTime.Kindに設定される値とその意味は次のようになります。
DateTimeKind | 意味 |
---|---|
DateTimeKind.Local | DateTimeの時刻はローカル時刻を表す |
DateTimeKind.Utc | DateTimeの時刻はUTCでの時刻を表す |
DateTimeKind.Unspecified | 時刻の種類が特に指定されていない、あるいはどちらでもない |
DateTimeで時刻の変換を行う際にはこのプロパティの値が参照され、例えばローカル時刻またはUTCへの変換を行うToUniversalTime・ToLocalTimeメソッドでは、このKindプロパティの値に応じて適切な時刻に値が変換されます。
DateTimeのコンストラクタでは、時刻がローカル時刻・UTCのどちらを表すのか明示するためにDateTimeKindを指定することが出来ます。 また、DateTime.Nowプロパティで取得できる現在日時はDateTimeKind.Local、DateTime.UtcNowプロパティではDateTimeKind.Utcとなります。
using System;
class Sample {
static void Main()
{
var a = new DateTime(2013, 4, 1, 15, 0, 30, 123); // 日時の種類を指定しない
var b = new DateTime(2013, 4, 1, 15, 0, 30, 123, DateTimeKind.Local); // ローカル時刻として日時を指定
var c = new DateTime(2013, 4, 1, 15, 0, 30, 123, DateTimeKind.Utc); // UTCとして日時を指定
var d = DateTime.Now; // ローカル時刻での現在日時を取得
var e = DateTime.UtcNow; // UTCでの現在日時を取得
foreach (var dt in new[] {a, b, c, d, e}) {
Console.WriteLine("{0} {1}", dt, dt.Kind);
}
}
}
Imports System
Class Sample
Shared Sub Main()
Dim a As New DateTime(2013, 4, 1, 15, 0, 30, 123) ' 日時の種類を指定しない
Dim b As New DateTime(2013, 4, 1, 15, 0, 30, 123, DateTimeKind.Local) ' ローカル時刻として日時を指定
Dim c As New DateTime(2013, 4, 1, 15, 0, 30, 123, DateTimeKind.Utc) ' UTCとして日時を指定
Dim d As DateTime = DateTime.Now ' ローカル時刻での現在日時を取得
Dim e As DateTime = DateTime.UtcNow ' UTCでの現在日時を取得
For Each dt As DateTime In New DateTime() {a, b, c, d, e}
Console.WriteLine("{0} {1}", dt, dt.Kind)
Next
End Sub
End Class
2013/04/01 15:00:30 Unspecified 2013/04/01 15:00:30 Local 2013/04/01 15:00:30 Utc 2013/04/01 15:30:05 Local 2013/04/01 6:30:05 Utc
DateTime.Parseメソッドで文字列から日時を読み取りDateTimeを作成する場合にも、文字列に指定されているタイムゾーン部分を判別して適当なDateTimeKindが設定されます。
using System;
class Sample {
static void Main()
{
var a = "2013-04-01T15:00:30"; // オフセット表記の無い日時
var b = "2013-04-01T15:00:30-05:00"; // オフセット表記のある日時
var c = "2013-04-01T15:00:30Z"; // UTCでの日時
foreach (var s in new[] {a, b, c}) {
// 文字列からDateTimeに変換
var dt = DateTime.Parse(s);
Console.WriteLine("{0} {1}", dt, dt.Kind);
}
Console.WriteLine();
}
}
Imports System
Class Sample
Shared Sub Main()
Dim a As String = "2013-04-01T15:00:30" ' オフセット表記の無い日時
Dim b As String = "2013-04-01T15:00:30-05:00" ' オフセット表記のある日時
Dim c As String = "2013-04-01T15:00:30Z" ' UTCでの日時
For Each s As String In New String() {a, b, c}
' 文字列からDateTimeに変換
Dim dt As DateTime = DateTime.Parse(s)
Console.WriteLine("{0} {1}", dt, dt.Kind)
Next
Console.WriteLine()
End Sub
End Class
2013/04/01 15:00:30 Unspecified 2013/04/02 5:00:30 Local 2013/04/02 0:00:30 Local
Parseメソッドで文字列からDateTimeに変換する場合、デフォルトではローカル時刻(オフセット表記のある場合)またはUnspecified(オフセット表記のない場合)に変換されますが、オプションで変換の際に時刻の種類をどう扱うかを変更することができます。 詳しくは日時・文字列の変換と書式 §.変換時のオプション (DateTimeStyles)で解説します。
時刻の種類の変更
時刻の種類(Kindプロパティの値)はインスタンス作成時に設定された後は一切変更することができません。 ですが、DateTime.SpecifyKindメソッドを使うと日時部分はそのままで、Kindプロパティの値だけを指定した値に変更したDateTimeを取得することが出来ます。
using System;
class Sample {
static void Main()
{
var a = new DateTime(2013, 4, 1, 15, 0, 30, 123, DateTimeKind.Local);
var b = new DateTime(2013, 4, 1, 15, 0, 30, 123, DateTimeKind.Utc);
var c = new DateTime(2013, 4, 1, 15, 0, 30, 123); // DateTimeKind.Unspecified
var kinds = new[] {
DateTimeKind.Local,
DateTimeKind.Utc,
DateTimeKind.Unspecified,
};
foreach (var kind in kinds) {
Console.WriteLine("SpecifyKind({0})", kind);
foreach (DateTime dt in new DateTime[] {a, b, c}) {
// SpecifyKindメソッドでKindの値を変更したDateTimeを取得する
DateTime dtNew = DateTime.SpecifyKind(dt, kind);
Console.WriteLine("{0} {1,-12} -> {2} {3}", dt, dt.Kind, dtNew, dtNew.Kind);
}
Console.WriteLine();
}
}
}
Imports System
Class Sample
Shared Sub Main()
Dim a As New DateTime(2013, 4, 1, 15, 0, 30, 123, DateTimeKind.Local)
Dim b As New DateTime(2013, 4, 1, 15, 0, 30, 123, DateTimeKind.Utc)
Dim c As New DateTime(2013, 4, 1, 15, 0, 30, 123) ' DateTimeKind.Unspecified
Dim kinds() As DateTimeKind = New DateTimeKind() { _
DateTimeKind.Local, _
DateTimeKind.Utc, _
DateTimeKind.Unspecified _
}
For Each kind As DateTimeKind In kinds
Console.WriteLine("SpecifyKind({0})", kind)
For Each dt As DateTime In New DateTime() {a, b, c}
' SpecifyKindメソッドでKindの値を変更したDateTimeを取得する
Dim dtNew As DateTime = DateTime.SpecifyKind(dt, kind)
Console.WriteLine("{0} {1,-12} -> {2} {3}", dt, dt.Kind, dtNew, dtNew.Kind)
Next
Console.WriteLine()
Next
End Sub
End Class
SpecifyKind(Local) 2013/04/01 15:00:30 Local -> 2013/04/01 15:00:30 Local 2013/04/01 15:00:30 Utc -> 2013/04/01 15:00:30 Local 2013/04/01 15:00:30 Unspecified -> 2013/04/01 15:00:30 Local SpecifyKind(Utc) 2013/04/01 15:00:30 Local -> 2013/04/01 15:00:30 Utc 2013/04/01 15:00:30 Utc -> 2013/04/01 15:00:30 Utc 2013/04/01 15:00:30 Unspecified -> 2013/04/01 15:00:30 Utc SpecifyKind(Unspecified) 2013/04/01 15:00:30 Local -> 2013/04/01 15:00:30 Unspecified 2013/04/01 15:00:30 Utc -> 2013/04/01 15:00:30 Unspecified 2013/04/01 15:00:30 Unspecified -> 2013/04/01 15:00:30 Unspecified
このメソッドはDateTimeの日時の部分は変更せず、Kindプロパティの値のみを変更します。 つまり、変更に際してUTCとローカル時刻間の時差は考慮されません。 そのため、このメソッドの主な目的は、DateTimeから時刻の種類の情報を切り離したい場合、あるいは時刻の種類が設定されていない(Unspecifiedな)状態のDateTimeに時刻の種類を設定することになります。
一方、UTCとローカル時刻間での時差を考慮した上で変更したい場合はToUniversalTime・ToLocalTimeメソッドを使います。
DateTimeOffset.Offset
DateTimeOffsetでは、時刻は常にいずれかのタイムゾーンでの時刻を表す(UTCからの時差を持つ)ものとして扱われるため、時刻の種類という概念はありません。 そのかわり、タイムゾーンに対応するオフセット値を表すプロパティOffsetが用意されています。
このプロパティはUTCからの時差をTimeSpanとして表し、例えばDateTimeOffsetの表す日時がUTCの場合、Offsetプロパティの値は +00:00:00 (TimeSpan.Zero)になります。 また、実行環境の時刻が日本標準時(UTC+9)に設定されている環境の場合、DateTimeOffset.NowプロパティはOffsetに +09:00:00 が設定された値を返します。
なお、DateTimeOffset.DateTimeプロパティを参照すると、DateTimeOffsetからオフセット値部分を除いて日時部分だけにしたDateTimeを取得できます。 このプロパティで取得できるDateTimeのKindプロパティの値は、DateTimeKind.Unspecifiedとなります。
using System;
class Sample {
static void Main()
{
var dt = new DateTime(2013, 4, 1, 15, 0, 30, 123);
var a = new DateTimeOffset(dt, TimeSpan.Zero); // UTC+0の日時を指定
var b = new DateTimeOffset(dt, new TimeSpan(-5, 0, 0)); // UTC-5(東部標準時)の日時を指定
var c = new DateTimeOffset(dt, new TimeSpan(+9, 0, 0)); // UTC+9(日本標準時)の日時を指定
var d = DateTimeOffset.Now; // ローカル時刻での現在日時を取得
var e = DateTimeOffset.UtcNow; // UTCでの現在日時を取得
foreach (var dto in new[] {a, b, c, d, e}) {
Console.WriteLine("{0}, {1}", dto.DateTime, dto.Offset);
}
}
}
Imports System
Class Sample
Shared Sub Main()
Dim dt As New DateTime(2013, 4, 1, 15, 0, 30, 123)
Dim a As New DateTimeOffset(dt, TimeSpan.Zero) ' UTC+0の日時を指定
Dim b As New DateTimeOffset(dt, new TimeSpan(-5, 0, 0)) ' UTC-5(東部標準時)の日時を指定
Dim c As New DateTimeOffset(dt, new TimeSpan(+9, 0, 0)) ' UTC+9(日本標準時)の日時を指定
Dim d As DateTimeOffset = DateTimeOffset.Now ' ローカル時刻での現在日時を取得
Dim e As DateTimeOffset = DateTimeOffset.UtcNow ' UTCでの現在日時を取得
For Each dto As DateTimeOffset In New DateTimeOffset() {a, b, c, d, e}
Console.WriteLine("{0}, {1}", dto.DateTime, dto.Offset)
Next
End Sub
End Class
2013/04/01 15:00:30, 00:00:00 2013/04/01 15:00:30, -05:00:00 2013/04/01 15:00:30, 09:00:00 2013/04/01 15:30:05, 09:00:00 2013/04/01 6:30:05, 00:00:00
DateTimeOffset.Parseメソッドで文字列から日時を読み取りDateTimeOffsetを作成する場合、文字列中にオフセット値が指定されていれば、その値がOffsetプロパティの値となります。
using System;
class Sample {
static void Main()
{
var a = "2013-04-01T15:00:30"; // オフセット表記の無い日時
var b = "2013-04-01T15:00:30-05:00"; // オフセット表記のある日時
var c = "2013-04-01T15:00:30Z"; // UTCでの日時
foreach (var s in new string[] {a, b, c}) {
// 文字列からDateTimeOffsetに変換
DateTimeOffset dto = DateTimeOffset.Parse(s);
Console.WriteLine("{0}, {1}", dto.DateTime, dto.Offset);
}
Console.WriteLine();
}
}
Imports System
Class Sample
Shared Sub Main()
Dim a As String = "2013-04-01T15:00:30" ' オフセット表記の無い日時
Dim b As String = "2013-04-01T15:00:30-05:00" ' オフセット表記のある日時
Dim c As String = "2013-04-01T15:00:30Z" ' UTCでの日時
For Each s As String In New String() {a,b, c}
' 文字列からDateTimeOffsetに変換
Dim dto As DateTimeOffset = DateTimeOffset.Parse(s)
Console.WriteLine("{0}, {1}", dto.DateTime, dto.Offset)
Next
Console.WriteLine()
End Sub
End Class
2013/04/01 15:00:30, 09:00:00 2013/04/01 15:00:30, -05:00:00 2013/04/01 15:00:30, 09:00:00
Parseメソッドで文字列からDateTimeOffsetに変換する場合、オフセット表記がない場合はデフォルトではローカル時刻であるものとして変換されますが、オプションで変換の際にオフセット値をどう扱うかを変更することができます。 詳しくは日時・文字列の変換と書式 §.変換時のオプション (DateTimeStyles)で解説します。
ローカル時刻・UTCへの変換
DateTime・DateTimeOffsetの表す時刻をローカル時刻に変換するにはToLocalTimeメソッド、UTCに変換するにはToUniversalTimeメソッドを使うことが出来ます。 このメソッドは、インスタンスの表す時刻をローカル時刻・UTCに変換した結果を返します(元のインスタンスの状態は変化しません)。 DateTime・DateTimeOffsetではローカル時刻・UTCの表現に違いがあるため、時刻の変換を行う場合にもその動作に違いがあります。
DateTimeOffsetではローカル時刻・UTCへの変換の他に、特定のオフセット値での時刻に変換した値を取得するメソッドToOffsetを使うこともできます。
DateTime
DateTimeの表す時刻をToLocalTime・ToUniversalTimeメソッドで変換する場合、変換結果はKindプロパティの値によって変わります。 例えば、既にローカル時刻であるとされている値に対してToLocalTimeメソッドを呼び出しても得られる値は元の時刻と変わりませんが、ToUniversalTimeメソッドを呼び出せばUTCに変換された時刻が得られます。 DateTime.Kindの値とToLocalTime・ToUniversalTimeメソッドの結果は次のようになります。
DateTime.Kindの値 | ToLocalTimeの結果 | ToUniversalTimeの結果 |
---|---|---|
DateTimeKind.Local | 元の値と同じ | UTCに変換された値 |
DateTimeKind.Utc | ローカル時刻に変換された値 | 元の値と同じ |
DateTimeKind.Unspecified | (時刻の種類をUTCと仮定した上で) ローカル時刻に変換された値 |
(時刻の種類をローカル時刻と仮定した上で) UTCに変換された値 |
なお、ToLocalTimeメソッドが返すDateTimeのKindプロパティは当然DateTimeKind.Localとなります。 同様にToUniversalTimeはKindがDateTimeKind.UtcのDateTimeを返します。
以下の例はDateTimeKindが異なる日時のDateTimeに対してToLocalTime・ToUniversalTimeメソッドを呼び出した結果の違いを表示するものです。 なお、実行結果はタイムゾーンにUTC+9(日本標準時)が設定されている環境でのものです。
using System;
class Sample {
static void Main()
{
var a = new DateTime(2013, 4, 1, 15, 0, 30, 123, DateTimeKind.Local);
var b = new DateTime(2013, 4, 1, 15, 0, 30, 123, DateTimeKind.Utc);
var c = new DateTime(2013, 4, 1, 15, 0, 30, 123); // DateTimeKind.Unspecified
Console.WriteLine("[ToLocalTime]");
foreach (var dt in new[] {a, b, c}) {
var local = dt.ToLocalTime(); // 時刻をローカル時刻に変換
Console.WriteLine("{0} {1,-12} -> {2} {3}", dt, dt.Kind, local, local.Kind);
}
Console.WriteLine();
Console.WriteLine("[ToUniversalTime]");
foreach (var dt in new[] {a, b, c}) {
var utc = dt.ToUniversalTime(); // 時刻をUTCに変換
Console.WriteLine("{0} {1,-12} -> {2} {3}", dt, dt.Kind, utc, utc.Kind);
}
}
}
Imports System
Class Sample
Shared Sub Main()
Dim a As New DateTime(2013, 4, 1, 15, 0, 30, 123, DateTimeKind.Local)
Dim b As New DateTime(2013, 4, 1, 15, 0, 30, 123, DateTimeKind.Utc)
Dim c As New DateTime(2013, 4, 1, 15, 0, 30, 123) ' DateTimeKind.Unspecified
Console.WriteLine("[ToLocalTime]")
For Each dt As DateTime In New DateTime() {a, b, c}
Dim local As DateTime = dt.ToLocalTime() ' 時刻をローカル時刻に変換
Console.WriteLine("{0} {1,-12} -> {2} {3}", dt, dt.Kind, local, local.Kind)
Next
Console.WriteLine()
Console.WriteLine("[ToUniversalTime]")
For Each dt As DateTime In New DateTime() {a, b, c}
Dim utc As DateTime = dt.ToUniversalTime() ' 時刻をUTCに変換
Console.WriteLine("{0} {1,-12} -> {2} {3}", dt, dt.Kind, utc, utc.Kind)
Next
End Sub
End Class
[ToLocalTime] 2013/04/01 15:00:30 Local -> 2013/04/01 15:00:30 Local 2013/04/01 15:00:30 Utc -> 2013/04/02 0:00:30 Local 2013/04/01 15:00:30 Unspecified -> 2013/04/02 0:00:30 Local [ToUniversalTime] 2013/04/01 15:00:30 Local -> 2013/04/01 6:00:30 Utc 2013/04/01 15:00:30 Utc -> 2013/04/01 15:00:30 Utc 2013/04/01 15:00:30 Unspecified -> 2013/04/01 6:00:30 Utc
日時の変換を行わずにKindプロパティの設定値のみを変更したい場合は、SpecifyKindメソッドを使います。
DateTimeOffset
DateTimeOffsetでは、LocalDateTimeおよびUtcDateTimeプロパティを参照することでローカル時刻・UTCでの値を取得することが出来ます。 ただし、このプロパティではDateTimeでの値が返されるため、オフセット情報が消失した値となります。 LocalDateTimeプロパティではDateTime.KindプロパティにDateTimeKind.Local、UtcDateTimeプロパティではDateTimeKind.UtcがセットされたDateTimeが返されます。
using System;
class Sample {
static void Main()
{
var dto = new DateTimeOffset(2013, 4, 1, 15, 0, 30, 123, new TimeSpan(-5, 0, 0)); // UTC-5(EST、東部標準時)での時刻
Console.WriteLine(dto);
Console.WriteLine(dto.LocalDateTime);
Console.WriteLine(dto.UtcDateTime);
}
}
Imports System
Class Sample
Shared Sub Main()
Dim dto As New DateTimeOffset(2013, 4, 1, 15, 0, 30, 123, new TimeSpan(-5, 0, 0)) ' UTC-5(EST、東部標準時)での時刻
Console.WriteLine(dto)
Console.WriteLine(dto.LocalDateTime)
Console.WriteLine(dto.UtcDateTime)
End Sub
End Class
2013/04/01 15:00:30 -05:00 2013/04/02 5:00:30 2013/04/01 20:00:30
DateTimeOffsetでも、DateTimeの場合と同様にToLocalTime・ToUniversalTimeメソッドで時刻を変換することができます。 さらに、ToOffsetメソッドで任意のオフセット値に変更した時刻に変換することも出来ます。
ToLocalTimeメソッドが返すDateTimeOffsetのOffsetプロパティは当然ローカル時刻のオフセット値と同じになります。 同様にToUniversalTimeはOffsetが 00:00:00 のDateTimeOffsetを返し、ToOffsetは指定したオフセット値が設定されたDateTimeOffsetを返します。
以下の例は、オフセット値が異なる日時のDateTimeOffsetに対してToLocalTime・ToUniversalTime・ToOffsetの各メソッドを呼び出した結果の違いを表示するものです。 なお、実行結果はタイムゾーンにUTC+9(日本標準時)が設定されている環境でのものです。
using System;
class Sample {
static void Main()
{
var a = new DateTimeOffset(2013, 4, 1, 15, 0, 30, 123, new TimeSpan(+9, 0, 0));
var b = new DateTimeOffset(2013, 4, 1, 15, 0, 30, 123, new TimeSpan(-5, 0, 0));
var c = new DateTimeOffset(2013, 4, 1, 15, 0, 30, 123, TimeSpan.Zero);
Console.WriteLine("[ToLocalTime]");
foreach (var dto in new[] {a, b, c}) {
var local = dto.ToLocalTime(); // 時刻をローカル時刻に変換
Console.WriteLine("{0} -> {1}", dto, local);
}
Console.WriteLine();
Console.WriteLine("[ToUniversalTime]");
foreach (var dto in new[] {a, b, c}) {
var utc = dto.ToUniversalTime();
Console.WriteLine("{0} -> {1}", dto, utc); // 時刻をUTCに変換
}
Console.WriteLine();
Console.WriteLine("[ToOffset]");
foreach (var dto in new[] {a, b, c}) {
var est = dto.ToOffset(new TimeSpan(-5, 0, 0)); // 時刻をUTC-5(EST、東部標準時)に変換
Console.WriteLine("{0} -> {1}", dto, est);
}
}
}
Imports System
Class Sample
Shared Sub Main()
Dim a As New DateTimeOffset(2013, 4, 1, 15, 0, 30, 123, new TimeSpan(+9, 0, 0))
Dim b As New DateTimeOffset(2013, 4, 1, 15, 0, 30, 123, new TimeSpan(-5, 0, 0))
Dim c As New DateTimeOffset(2013, 4, 1, 15, 0, 30, 123, TimeSpan.Zero)
Console.WriteLine("[ToLocalTime]")
For Each dto As DateTimeOffset In New DateTimeOffset() {a, b, c}
Dim local As DateTimeOffset = dto.ToLocalTime() ' 時刻をローカル時刻に変換
Console.WriteLine("{0} -> {1}", dto, local)
Next
Console.WriteLine()
Console.WriteLine("[ToUniversalTime]")
For Each dto As DateTimeOffset In New DateTimeOffset() {a, b, c}
Dim utc As DateTimeOffset = dto.ToUniversalTime()
Console.WriteLine("{0} -> {1}", dto, utc) ' 時刻をUTCに変換
Next
Console.WriteLine()
Console.WriteLine("[ToOffset]")
For Each dto As DateTimeOffset In New DateTimeOffset() {a, b, c}
Dim est As DateTimeOffset = dto.ToOffset(new TimeSpan(-5, 0, 0)) ' 時刻をUTC-5(EST、東部標準時)に変換
Console.WriteLine("{0} -> {1}", dto, est)
Next
End Sub
End Class
[ToLocalTime] 2013/04/01 15:00:30 +09:00 -> 2013/04/01 15:00:30 +09:00 2013/04/01 15:00:30 -05:00 -> 2013/04/02 5:00:30 +09:00 2013/04/01 15:00:30 +00:00 -> 2013/04/02 0:00:30 +09:00 [ToUniversalTime] 2013/04/01 15:00:30 +09:00 -> 2013/04/01 6:00:30 +00:00 2013/04/01 15:00:30 -05:00 -> 2013/04/01 20:00:30 +00:00 2013/04/01 15:00:30 +00:00 -> 2013/04/01 15:00:30 +00:00 [ToOffset] 2013/04/01 15:00:30 +09:00 -> 2013/04/01 1:00:30 -05:00 2013/04/01 15:00:30 -05:00 -> 2013/04/01 15:00:30 -05:00 2013/04/01 15:00:30 +00:00 -> 2013/04/01 10:00:30 -05:00
ToLocalTimeメソッドでは、実行環境に設定されているタイムゾーンに従って夏時間等の時間調整を考慮した変換が行われます。 一方、ToOffsetメソッドでは、単に指定されたオフセット値への変換のみが行われ、夏時間等の考慮はされません。 夏時間等の調整が必要なタイムゾーンへの変換を行う場合は、TimeZoneInfo.ConvertTimeメソッドを使う必要があります。
TimeZoneInfo
TimeZoneInfoクラスは、.NET Framework 3.5から導入されたクラスです。 TimeZoneInfoでは特定のタイムゾーンに関する情報を扱い、日時をそのタイムゾーンでのものに変換するメソッドなどが用意されています。
タイムゾーンとその情報の取得
TimeZoneInfoクラスでは、タイムゾーンの名称(StandardNameプロパティ)、タイムゾーンにおける標準時とUTCとの差(オフセット値、BaseUtcOffsetプロパティ)、タイムゾーンに夏時間が存在するかどうか(SupportsDaylightSavingTimeプロパティ)、といった情報を参照することが出来ます。
次の例では、実行環境に設定されているタイムゾーンをLocalプロパティで取得し、その情報を表示しています。
using System;
class Sample {
static void Main()
{
// ローカルタイムゾーンの情報を取得
var local = TimeZoneInfo.Local;
Console.WriteLine("StandardName: {0}", local.StandardName);
Console.WriteLine("DisplayName: {0}", local.DisplayName);
Console.WriteLine("BaseUtcOffset: {0}", local.BaseUtcOffset);
Console.WriteLine("SupportsDaylightSavingTime: {0}", local.SupportsDaylightSavingTime);
}
}
Imports System
Class Sample
Shared Sub Main()
' ローカルタイムゾーンの情報を取得
Dim local As TimeZoneInfo = TimeZoneInfo.Local
Console.WriteLine("StandardName: {0}", local.StandardName)
Console.WriteLine("DisplayName: {0}", local.DisplayName)
Console.WriteLine("BaseUtcOffset: {0}", local.BaseUtcOffset)
Console.WriteLine("SupportsDaylightSavingTime: {0}", local.SupportsDaylightSavingTime)
End Sub
End Class
StandardName: 東京 (標準時) DisplayName: (UTC+09:00) 大阪、札幌、東京 BaseUtcOffset: 09:00:00 SupportsDaylightSavingTime: False
StandardName: 日本標準時 DisplayName: 日本標準時 BaseUtcOffset: 09:00:00 SupportsDaylightSavingTime: True
StandardName: JST DisplayName: JST BaseUtcOffset: 09:00:00 SupportsDaylightSavingTime: True
ローカルタイムゾーン以外を表すTimeZoneInfoを取得したい場合は、FindSystemTimeZoneByIdメソッドに目的のタイムゾーンのIDを指定して取得します。 Windowsでは、レジストリに格納されている情報を元にTimeZoneInfoが取得されます。 FindSystemTimeZoneByIdメソッドでは、該当するタイムゾーンが見つからない場合、例外TimeZoneNotFoundExceptionがスローされます。
このほか、Localプロパティと同様、Utcプロパティを参照すれば、UTCのタイムゾーンを表すTimeZoneInfoを取得することが出来ます。
using System;
class Sample {
static void Main()
{
var timezones = new[] {
TimeZoneInfo.Local,
TimeZoneInfo.Utc,
};
foreach (var tz in timezones) {
Console.WriteLine("{0} ({1}) {2}", tz.StandardName, tz.BaseUtcOffset, tz.DisplayName);
}
Console.WriteLine();
// IDからTimeZoneInfoを取得
var ids = new[] {
"JST", "Tokyo Standard Time", "Asia/Tokyo",
"EST", "Eastern Standard Time", "America/New_York",
"GMT", "GMT Standard Time", "Europe/London",
};
foreach (var id in ids) {
Console.Write("{0,-25} -> ", id);
try {
var tz = TimeZoneInfo.FindSystemTimeZoneById(id);
Console.WriteLine("{0} ({1}) {2}", tz.StandardName, tz.BaseUtcOffset, tz.DisplayName);
}
catch (TimeZoneNotFoundException) {
Console.WriteLine("(time zone not found)");
}
}
}
}
Imports System
Class Sample
Shared Sub Main()
Dim timezones() As TimeZoneInfo = New TimeZoneInfo() { _
TimeZoneInfo.Local, _
TimeZoneInfo.Utc _
}
For Each tz In timezones
Console.WriteLine("{0} ({1}) {2}", tz.StandardName, tz.BaseUtcOffset, tz.DisplayName)
Next
Console.WriteLine()
' IDからTimeZoneInfoを取得
Dim ids() As String = New String() { _
"JST", "Tokyo Standard Time", "Asia/Tokyo", _
"EST", "Eastern Standard Time", "America/New_York", _
"GMT", "GMT Standard Time", "Europe/London" _
}
For Each id As String In ids
Console.Write("{0,-25} -> ", id)
Try
Dim tz As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(id)
Console.WriteLine("{0} ({1}) {2}", tz.StandardName, tz.BaseUtcOffset, tz.DisplayName)
Catch ex As TimeZoneNotFoundException
Console.WriteLine("(time zone not found)")
End Try
Next
End Sub
End Class
東京 (標準時) (09:00:00) (UTC+09:00) 大阪、札幌、東京 UTC (00:00:00) UTC JST -> (time zone not found) Tokyo Standard Time -> 東京 (標準時) (09:00:00) (UTC+09:00) 大阪、札幌、東京 Asia/Tokyo -> (time zone not found) EST -> (time zone not found) Eastern Standard Time -> 東部標準時 (-05:00:00) (UTC-05:00) 東部標準時 (米国およびカナダ) America/New_York -> (time zone not found) GMT -> (time zone not found) GMT Standard Time -> GMT 標準時 (00:00:00) (UTC+00:00) ダブリン、エジンバラ、リスボン、ロンドン Europe/London -> (time zone not found)
日本標準時 (09:00:00) 日本標準時 UTC (00:00:00) UTC JST -> (time zone not found) Tokyo Standard Time -> (time zone not found) Asia/Tokyo -> 日本標準時 (09:00:00) 日本標準時 EST -> GMT-05:00 (-05:00:00) GMT-05:00 Eastern Standard Time -> (time zone not found) America/New_York -> アメリカ東部標準時 (-05:00:00) アメリカ東部標準時 GMT -> グリニッジ標準時 (00:00:00) グリニッジ標準時 GMT Standard Time -> (time zone not found) Europe/London -> グリニッジ標準時 (00:00:00) グリニッジ標準時
JST (09:00:00) JST UTC (00:00:00) UTC JST -> (time zone not found) Tokyo Standard Time -> (time zone not found) Asia/Tokyo -> JST (09:00:00) JST EST -> EST (-05:00:00) EST Eastern Standard Time -> (time zone not found) America/New_York -> EST (-05:00:00) EST GMT -> GMT (00:00:00) GMT GMT Standard Time -> (time zone not found) Europe/London -> GMT (00:00:00) GMT
FindSystemTimeZoneByIdメソッドでは、システムに保存されているタイムゾーン情報の形式の違いにより、WindowsではJST
やTokyo Standard Time
といったタイムゾーン名を、Linux等ではAsia/Tokyo
といった地域/都市名の表記を指定する必要があります。
システムで使用可能なすべてのタイムゾーンを取得するには、GetSystemTimeZonesメソッドを使います。
日時の変換
ConvertTimeメソッドを使うと、DateTime・DateTimeOffsetの値を異なるタイムゾーンでの日時に変換することができます。
DateTimeOffset.Offsetメソッドではオフセット値の変更はできますが、この際、夏時間などタイムゾーン内での時間調整は一切行われません。 一方TimeZoneInfo.ConvertTimeメソッドでは、変換に際してそのタイムゾーン内での時刻の変換規則に基づいた時間調整が行われます。 DateTimeOffsetだけでなく、DateTimeに対しても同様に時間調整が行われます。
using System;
class Sample {
static void Main()
{
// 東部標準時のTimeZoneInfoを取得
var est = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
// ローカルでの冬期・夏期の日付 (DateTime)
var dtWinter = new DateTime(2013, 1, 1, 12, 0, 0, DateTimeKind.Local);
var dtSummer = new DateTime(2013, 7, 1, 12, 0, 0, DateTimeKind.Local);
Console.WriteLine("{0} -> {1} {2}",
dtWinter,
est.IsDaylightSavingTime(dtWinter) ? est.DaylightName : est.StandardName,
TimeZoneInfo.ConvertTime(dtWinter, est));
Console.WriteLine("{0} -> {1} {2}",
dtSummer,
est.IsDaylightSavingTime(dtSummer) ? est.DaylightName : est.StandardName,
TimeZoneInfo.ConvertTime(dtSummer, est));
Console.WriteLine();
// ローカルでの冬期・夏期の日付 (DateTimeOffset)
var dtoWinter = new DateTimeOffset(2013, 1, 1, 12, 0, 0, TimeZoneInfo.Local.BaseUtcOffset);
var dtoSummer = new DateTimeOffset(2013, 7, 1, 12, 0, 0, TimeZoneInfo.Local.BaseUtcOffset);
Console.WriteLine("{0} -> {1} {2}",
dtoWinter,
est.IsDaylightSavingTime(dtoWinter) ? est.DaylightName : est.StandardName,
TimeZoneInfo.ConvertTime(dtoWinter, est));
Console.WriteLine("{0} -> {1} {2}",
dtoSummer,
est.IsDaylightSavingTime(dtoSummer) ? est.DaylightName : est.StandardName,
TimeZoneInfo.ConvertTime(dtoSummer, est));
}
}
Imports System
Class Sample
Shared Sub Main()
' 東部標準時のTimeZoneInfoを取得
Dim est As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time")
' ローカルでの冬期・夏期の日付 (DateTime)
Dim dtWinter As New DateTime(2013, 1, 1, 12, 0, 0, DateTimeKind.Local)
Dim dtSummer As New DateTime(2013, 7, 1, 12, 0, 0, DateTimeKind.Local)
Console.WriteLine("{0} -> {1} {2}", _
dtWinter, _
IIf(est.IsDaylightSavingTime(dtWinter), est.DaylightName, est.StandardName), _
TimeZoneInfo.ConvertTime(dtWinter, est))
Console.WriteLine("{0} -> {1} {2}", _
dtSummer, _
IIf(est.IsDaylightSavingTime(dtSummer), est.DaylightName, est.StandardName), _
TimeZoneInfo.ConvertTime(dtSummer, est))
Console.WriteLine()
' ローカルでの冬期・夏期の日付 (DateTimeOffset)
Dim dtoWinter As New DateTimeOffset(2013, 1, 1, 12, 0, 0, TimeZoneInfo.Local.BaseUtcOffset)
Dim dtoSummer As New DateTimeOffset(2013, 7, 1, 12, 0, 0, TimeZoneInfo.Local.BaseUtcOffset)
Console.WriteLine("{0} -> {1} {2}", _
dtoWinter, _
IIf(est.IsDaylightSavingTime(dtoWinter), est.DaylightName, est.StandardName), _
TimeZoneInfo.ConvertTime(dtoWinter, est))
Console.WriteLine("{0} -> {1} {2}", _
dtoSummer, _
IIf(est.IsDaylightSavingTime(dtoSummer), est.DaylightName, est.StandardName), _
TimeZoneInfo.ConvertTime(dtoSummer, est))
End Sub
End Class
2013/01/01 12:00:00 -> 東部標準時 2012/12/31 22:00:00 2013/07/01 12:00:00 -> 東部夏時間 2013/06/30 23:00:00 2013/01/01 12:00:00 +09:00 -> 東部標準時 2012/12/31 22:00:00 -05:00 2013/07/01 12:00:00 +09:00 -> 東部夏時間 2013/06/30 23:00:00 -04:00
あるタイムゾーンにて日時が夏時間の期間中かどうかを調べるには、IsDaylightSavingTimeメソッドが使えます。
さらに、ConvertTimeBySystemTimeZoneIdメソッドを使えば、目的のタイムゾーンを表すTimeZoneInfoの取得を省略することが出来ます。 このメソッドは、FindSystemTimeZoneByIdメソッドとConvertTimeメソッドの組み合わせと同等であるため、呼び出しが1度であるならこちらのメソッドを使った方が記述が少なくなります。
using System;
class Sample {
static void Main()
{
// 東部標準時のID
const string est = "Eastern Standard Time";
// ローカルでの冬期・夏期の日付 (DateTime)
var dtWinter = new DateTime(2013, 1, 1, 12, 0, 0, DateTimeKind.Local);
var dtSummer = new DateTime(2013, 7, 1, 12, 0, 0, DateTimeKind.Local);
Console.WriteLine("{0} -> {1}",
dtWinter,
TimeZoneInfo.ConvertTimeBySystemTimeZoneId(dtWinter, est));
Console.WriteLine("{0} -> {1}",
dtSummer,
TimeZoneInfo.ConvertTimeBySystemTimeZoneId(dtSummer, est));
Console.WriteLine();
// ローカルでの冬期・夏期の日付 (DateTimeOffset)
var dtoWinter = new DateTimeOffset(2013, 1, 1, 12, 0, 0, TimeZoneInfo.Local.BaseUtcOffset);
var dtoSummer = new DateTimeOffset(2013, 7, 1, 12, 0, 0, TimeZoneInfo.Local.BaseUtcOffset);
Console.WriteLine("{0} -> {1}",
dtoWinter,
TimeZoneInfo.ConvertTimeBySystemTimeZoneId(dtoWinter, est));
Console.WriteLine("{0} -> {1}",
dtoSummer,
TimeZoneInfo.ConvertTimeBySystemTimeZoneId(dtoSummer, est));
}
}
Imports System
Class Sample
Shared Sub Main()
' 東部標準時のID
Const est As String = "Eastern Standard Time"
' ローカルでの冬期・夏期の日付 (DateTime)
Dim dtWinter As New DateTime(2013, 1, 1, 12, 0, 0, DateTimeKind.Local)
Dim dtSummer As New DateTime(2013, 7, 1, 12, 0, 0, DateTimeKind.Local)
Console.WriteLine("{0} -> {1}", _
dtWinter, _
TimeZoneInfo.ConvertTimeBySystemTimeZoneId(dtWinter, est))
Console.WriteLine("{0} -> {1}", _
dtSummer, _
TimeZoneInfo.ConvertTimeBySystemTimeZoneId(dtSummer, est))
Console.WriteLine()
' ローカルでの冬期・夏期の日付 (DateTimeOffset)
Dim dtoWinter As New DateTimeOffset(2013, 1, 1, 12, 0, 0, TimeZoneInfo.Local.BaseUtcOffset)
Dim dtoSummer As New DateTimeOffset(2013, 7, 1, 12, 0, 0, TimeZoneInfo.Local.BaseUtcOffset)
Console.WriteLine("{0} -> {1}", _
dtoWinter, _
TimeZoneInfo.ConvertTimeBySystemTimeZoneId(dtoWinter, est))
Console.WriteLine("{0} -> {1}", _
dtoSummer, _
TimeZoneInfo.ConvertTimeBySystemTimeZoneId(dtoSummer, est))
End Sub
End Class
2013/01/01 12:00:00 -> 2012/12/31 22:00:00 2013/07/01 12:00:00 -> 2013/06/30 23:00:00 2013/01/01 12:00:00 +09:00 -> 2012/12/31 22:00:00 -05:00 2013/07/01 12:00:00 +09:00 -> 2013/06/30 23:00:00 -04:00