この記事の英語版を表示するには、[英語] のチェック ボックスをオンにしてください。また、テキストにマウス ポインターを合わせると、ポップアップ ウィンドウに英語のテキストを表示することもできます。
翻訳
英語

タイム ゾーン間での時刻の変換

 

タイム ゾーン間での日時の違いを処理するアプリケーションの重要性が増しています。 アプリケーションは、DateTime 構造体にある現地時刻ですべての時刻を表現するだけで良いとは想定できなくなりました。 たとえば、米国東部の現在時刻を表示する Web ページは、東アジアの顧客にとっては妥当なものではありません。 このトピックでは、あるタイム ゾーンから別のタイム ゾーンに時刻を変換する方法、およびタイム ゾーンの取り扱いが不適切な DateTimeOffset 値を変換する方法について説明します。

世界協定時刻 (UTC) は、高精度で、原子時計に基づく時刻基準です。 世界のタイム ゾーンは、UTC からの正または負のオフセットとして表されます。 したがって、UTC は、タイム ゾーンの影響を受けない時刻、またはどのタイム ゾーンからも中立の時刻を提供します。 コンピューター間での日時の統一性が重要な場合は、UTC 時刻を使用することをお勧めします。(日付と時刻を使用して詳細および他のベスト プラクティスについては、"参照して .NET Framework の DateTime を使用してコーディング Best Practicesください。個別のタイム ゾーンを UTC に変換すると、時刻の比較が容易になります。

System_CAPS_noteメモ

DateTimeOffset 構造体をシリアル化して、ある時刻を明確に表すこともできます。 DateTimeOffset オブジェクトは UTC からのオフセットで日時の値を格納するので、常に UTC に対する相対値で特定の時刻を表します。

時刻を UTC に変換する最も簡単な方法は、static (Visual Basic では Shared) の TimeZoneInfo.ConvertTimeToUtc(DateTime) メソッドを呼び出す方法です。 メソッドで実行される具体的な変換は、次の表に示すように、dateTime パラメーターの Kind プロパティの値によって決まります。

DateTime.Kind プロパティ

変換

DateTimeKind.Local

現地時刻を UTC に変換します。

DateTimeKind.Unspecified

dateTime パラメーターが現地時刻だと想定し、現地時刻を UTC に変換します。

DateTimeKind.Utc

dateTime パラメーターを変更しないで返します。

次に示すコードは、現在の現地時刻を UTC に変換し、結果をコンソールに表示します。

DateTime dateNow = DateTime.Now;
Console.WriteLine("The date and time are {0} UTC.", 
                   TimeZoneInfo.ConvertTimeToUtc(dateNow));
System_CAPS_noteメモ

TimeZoneInfo.ConvertTimeToUtc(DateTime) メソッドでは、TimeZone.ToUniversalTime メソッドおよび DateTime.ToUniversalTime メソッドと同一の結果が生成されるとは限りません。 ホスト システムのローカル タイム ゾーンに複数の調整規則が含まれる場合、TimeZoneInfo.ConvertTimeToUtc(DateTime) は、適切な規則を特定の日付および時刻に適用します。 他の 2 つのメソッドは、最新の調整規則を常に適用します。

日時値が現地時刻または UTC のどちらも表していない場合、ToUniversalTime メソッドは正しくない結果を返す可能性があります。 ただし、TimeZoneInfo.ConvertTimeToUtc メソッドを使用すると、指定したターム ゾーンから日時を変換できます。目的のタイム ゾーンを表す TimeZoneInfo オブジェクトを取得する方法の詳細については、「ローカル システムで定義されているタイム ゾーンの検索」を参照してください。次に示すコードでは、TimeZoneInfo.ConvertTimeToUtc メソッドを使用して、米国東部標準時を UTC に変換しています。

DateTime easternTime = new DateTime(2007, 01, 02, 12, 16, 00);
string easternZoneId = "Eastern Standard Time";
try
{
   TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId);
   Console.WriteLine("The date and time are {0} UTC.", 
                     TimeZoneInfo.ConvertTimeToUtc(easternTime, easternZone));
}
catch (TimeZoneNotFoundException)
{
   Console.WriteLine("Unable to find the {0} zone in the registry.", 
                     easternZoneId);
}                           
catch (InvalidTimeZoneException)
{
   Console.WriteLine("Registry data on the {0} zone has been corrupted.", 
                     easternZoneId);
}

DateTime オブジェクトの Kind プロパティとタイム ゾーンが一致してない場合、このメソッドは ArgumentException をスローします。 不一致が発生するのは、Kind プロパティが DateTimeKind.Local であるのに TimeZoneInfo オブジェクトがローカル タイム ゾーンを表していない場合、または Kind プロパティが DateTimeKind.Utc であるのに TimeZoneInfo オブジェクトが DateTimeKind.Utc と等しくない場合です。

これらのメソッドはすべて、DateTime 値をパラメーターとして受け取り、DateTime 値を返します。 DateTimeOffset 値の場合、DateTimeOffset 構造体には、現在のインスタンスの日時を UTC に変換する ToUniversalTime インスタンス メソッドがあります。次に示す例では、ToUniversalTime メソッドを呼び出して、現地時刻と他のいくつかの時刻を UTC に変換しています。

DateTimeOffset localTime, otherTime, universalTime;

// Define local time in local time zone
localTime = new DateTimeOffset(new DateTime(2007, 6, 15, 12, 0, 0));
Console.WriteLine("Local time: {0}", localTime);
Console.WriteLine();

// Convert local time to offset 0 and assign to otherTime
otherTime = localTime.ToOffset(TimeSpan.Zero);
Console.WriteLine("Other time: {0}", otherTime);
Console.WriteLine("{0} = {1}: {2}", 
                  localTime, otherTime, 
                  localTime.Equals(otherTime));
Console.WriteLine("{0} exactly equals {1}: {2}", 
                  localTime, otherTime, 
                  localTime.EqualsExact(otherTime));
Console.WriteLine();

// Convert other time to UTC
universalTime = localTime.ToUniversalTime(); 
Console.WriteLine("Universal time: {0}", universalTime);
Console.WriteLine("{0} = {1}: {2}", 
                  otherTime, universalTime, 
                  universalTime.Equals(otherTime));
Console.WriteLine("{0} exactly equals {1}: {2}", 
                  otherTime, universalTime, 
                  universalTime.EqualsExact(otherTime));
Console.WriteLine();
// The example produces the following output to the console:
//    Local time: 6/15/2007 12:00:00 PM -07:00
//    
//    Other time: 6/15/2007 7:00:00 PM +00:00
//    6/15/2007 12:00:00 PM -07:00 = 6/15/2007 7:00:00 PM +00:00: True
//    6/15/2007 12:00:00 PM -07:00 exactly equals 6/15/2007 7:00:00 PM +00:00: False
//    
//    Universal time: 6/15/2007 7:00:00 PM +00:00
//    6/15/2007 7:00:00 PM +00:00 = 6/15/2007 7:00:00 PM +00:00: True
//    6/15/2007 7:00:00 PM +00:00 exactly equals 6/15/2007 7:00:00 PM +00:00: True   

UTC から現地時刻への変換については、後の「UTC から現地時刻への変換」を参照してください。 任意のタイム ゾーンを指定して、UTC をそのタイム ゾーンの時刻に変換するには、ConvertTimeFromUtc メソッドを呼び出します。 このメソッドは、次の 2 つのパラメーターを受け取ります。

次に示すコードでは、UTC を米国中部標準時に変換しています。

DateTime timeUtc = DateTime.UtcNow;
try
{
   TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
   DateTime cstTime = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, cstZone);
   Console.WriteLine("The date and time are {0} {1}.", 
                     cstTime, 
                     cstZone.IsDaylightSavingTime(cstTime) ?
                             cstZone.DaylightName : cstZone.StandardName);
}
catch (TimeZoneNotFoundException)
{
   Console.WriteLine("The registry does not define the Central Standard Time zone.");
}                           
catch (InvalidTimeZoneException)
{
   Console.WriteLine("Registry data on the Central Standard Time zone has been corrupted.");
}

UTC を現地時刻に変換するには、変換する時刻を表す DateTime オブジェクトの ToLocalTime メソッドを呼び出します。 メソッドの具体的な動作は、次の表に示すように、オブジェクトの Kind プロパティの値によって異なります。

DateTime.Kind プロパティ

変換

DateTimeKind.Local

DateTime の値を変更しないで返します。

DateTimeKind.Unspecified

DateTime の値を UTC と想定し、UTC を現地時刻に変換します。

DateTimeKind.Utc

DateTime の値を現地時刻に変換します。

メモ   TimeZone.ToLocalTime メソッドの動作は、DateTime.ToLocalTime メソッドと同じです。受け取るパラメーターは、変換する日時の値 1 つだけです。

static (Visual Basic では Shared) TimeZoneInfo.ConvertTime メソッドを使用すると、任意のタイム ゾーンの時刻を指定して、現地時刻に変換することもできます。 この方法については、次のセクションで説明します。

次に示す TimeZoneInfo クラスの 2 つの static (Visual Basic では Shared) メソッドを使用すると、任意の 2 つのタイム ゾーン間で時刻を変換できます。

  • ConvertTime

    このメソッドのパラメーターは、変換する日時値、その日時値のタイム ゾーンを表す TimeZoneInfo オブジェクト、および変換後のタイム ゾーンを表す TimeZoneInfo オブジェクトです。

  • ConvertTimeBySystemTimeZoneId

    このメソッドのパラメーターは、変換する日時値、その日時値のタイム ゾーンの識別子、および変換後のタイム ゾーンの識別子です。

どちらのメソッドでも、変換する日時値の Kind プロパティと、もう 1 つの日時値に対応するタイム ゾーンを表す TimeZoneInfo オブジェクトまたはタイム ゾーン識別子が必要です。 それ以外の場合は、ArgumentException がスローされます。 たとえば、日時値の Kind プロパティが DateTimeKind.Local の場合、メソッドにパラメーターとして渡される TimeZoneInfo オブジェクトが TimeZoneInfo.Local ではないと、例外がスローされます。 また、メソッドにパラメーターとして渡される識別子が TimeZoneInfo.Local.Id に等しくない場合にも、例外がスローされます。

ConvertTime メソッドを使用してハワイ標準時を現地時刻に変換する例を次に示します。

DateTime hwTime = new DateTime(2007, 02, 01, 08, 00, 00);
try
{
   TimeZoneInfo hwZone = TimeZoneInfo.FindSystemTimeZoneById("Hawaiian Standard Time");
   Console.WriteLine("{0} {1} is {2} local time.", 
           hwTime, 
           hwZone.IsDaylightSavingTime(hwTime) ? hwZone.DaylightName : hwZone.StandardName, 
           TimeZoneInfo.ConvertTime(hwTime, hwZone, TimeZoneInfo.Local));
}
catch (TimeZoneNotFoundException)
{
   Console.WriteLine("The registry does not define the Hawaiian Standard Time zone.");
}                           
catch (InvalidTimeZoneException)
{
   Console.WriteLine("Registry data on the Hawaiian STandard Time zone has been corrupted.");
}

DateTimeOffset オブジェクトはインスタンス化されるときにタイム ゾーンとの関連付けを解除されるので、このオブジェクトによって表される日時値は、完全なタイム ゾーン対応ではありません。 ただし、多くの場合、アプリケーションで必要になるのは、特定のタイム ゾーンでの時刻ではなく、UTC に対する 2 つの異なるオフセットに基づいて日時を変換することだけです。 この変換は、現在のインスタンスの ToOffset メソッドを呼び出すことで実行できます。 このメソッドの唯一のパラメーターは、メソッドから返される新しい日時値のオフセットです。

たとえば、Web ページに対するユーザー要求の日時がわかっていて、MM/dd/yyyy hh:mm:ss zzzz の形式で文字列としてシリアル化されている場合、次の ReturnTimeOnServer メソッドは、この日時値を Web サーバーでの日時に変換します。

public DateTimeOffset ReturnTimeOnServer(string clientString)
{
   string format = @"M/d/yyyy H:m:s zzz";
   TimeSpan serverOffset = TimeZoneInfo.Local.GetUtcOffset(DateTimeOffset.Now);

   try
   {      
      DateTimeOffset clientTime = DateTimeOffset.ParseExact(clientString, format, CultureInfo.InvariantCulture);
      DateTimeOffset serverTime = clientTime.ToOffset(serverOffset);
      return serverTime;
   }
   catch (FormatException)
   {
      return DateTimeOffset.MinValue;
   }
}

メソッドが文字列に「9/1/5:32 の場合: 07 -05:00」、タイム ゾーンの時刻を UTC より 5 時間早い表す、9/1/3:32:を返します米国の太平洋標準時タイム ゾーンにあるサーバーの 07 年の場合は -07:00。

TimeZoneInfo クラスには、複数の DateTimeOffset 値を使用してタイム ゾーンの変換を実行する TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) メソッドのオーバーロードも含まれます。 このメソッドのパラメーターは、DateTimeOffset 値と、変換後のタイム ゾーンへの参照です。 このメソッドを呼び出すと、DateTimeOffset 値が返ります。 たとえば、前の例の ReturnTimeOnServer メソッドは、ConvertTime(DateTimeOffset, TimeZoneInfo) メソッドの呼び出しを使用して、次のように書き換えることができます。

public DateTimeOffset ReturnTimeOnServer(string clientString)
{
   string format = @"M/d/yyyy H:m:s zzz";

   try
   {      
      DateTimeOffset clientTime = DateTimeOffset.ParseExact(clientString, format, 
                                  CultureInfo.InvariantCulture);
      DateTimeOffset serverTime = TimeZoneInfo.ConvertTime(clientTime, 
                                  TimeZoneInfo.Local);
      return serverTime;
   }
   catch (FormatException)
   {
      return DateTimeOffset.MinValue;
   }
}
表示: