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

方法 : 日付と時刻の演算でタイム ゾーンを使用する

 

通常、DateTime 値または DateTimeOffset 値を使用して日付と時刻の演算を実行するとき、その結果にはタイム ゾーン調整規則は反映されません。 これは、日時の値のタイム ゾーンを明確に識別できる場合 (Kind プロパティが Local に設定されている場合など) でも同じです。 このトピックでは、特定のタイム ゾーンに属する日時の値の算術演算を実行する方法について説明します。 算術演算の結果には、タイム ゾーンの調整規則が反映されます。

日付と時刻の演算に調整規則を適用するには

  1. なんらかの方法を実装して、日時の値と、その値が属するタイム ゾーンを密接に結び付ます。 たとえば、日時の値とそのタイム ゾーンの両方を含む構造体を宣言します。 次の例では、この方法を使用して DateTime 値とそのタイム ゾーンをリンクします。

    // Define a structure for DateTime values for internal use only
    internal struct TimeWithTimeZone
    {
       TimeZoneInfo TimeZone;
       DateTime Time;
    }
    
  2. ConvertTimeToUtc メソッドまたは ConvertTime メソッドを呼び出して、時刻を世界協定時刻 (UTC: Coordinated Universal Time) に変換します。

  3. UTC 時刻で算術演算を実行します。

  4. TimeZoneInfo.ConvertTime(DateTime, TimeZoneInfo) メソッドを呼び出して、UTC の時刻から、元の時刻に関連付けられたタイム ゾーンの時刻に変換します。

使用例

次の例では、中部標準時の 2008 年 3 月 9 日午前 1 時 30 分に、2 時間 30 分を加えます。 夏時間 30 分にタイム ゾーンの移行が 2008 (3 年 12 月 9 日の午前 2:00 に、後で発生します。 例では、前のセクションに記載されている手順に従って 4 から 2008 年 1 月 3 日 9 時に午前 5:00 と、結果は正しい時刻を報告します。

using System;

public struct TimeZoneTime
{
   public TimeZoneInfo TimeZone;
   public DateTime Time;

   public TimeZoneTime(TimeZoneInfo tz, DateTime time)
   {
      if (tz == null) 
         throw new ArgumentNullException("The time zone cannot be a null reference.");

      this.TimeZone = tz;
      this.Time = time;   
   }

   public TimeZoneTime AddTime(TimeSpan interval)
   {
      // Convert time to UTC
      DateTime utcTime = TimeZoneInfo.ConvertTimeToUtc(this.Time, this.TimeZone);
      // Add time interval to time
      utcTime = utcTime.Add(interval);
      // Convert time back to time in time zone
      return new TimeZoneTime(this.TimeZone, TimeZoneInfo.ConvertTime(utcTime, 
                              TimeZoneInfo.Utc, this.TimeZone));
   }
}

public class TimeArithmetic
{
   public const string tzName = "Central Standard Time";

   public static void Main()
   {
      try
      {
         TimeZoneTime cstTime1, cstTime2;

         TimeZoneInfo cst = TimeZoneInfo.FindSystemTimeZoneById(tzName);
         DateTime time1 = new DateTime(2008, 3, 9, 1, 30, 0);          
         TimeSpan twoAndAHalfHours = new TimeSpan(2, 30, 0);

         cstTime1 = new TimeZoneTime(cst, time1);
         cstTime2 = cstTime1.AddTime(twoAndAHalfHours);
         Console.WriteLine("{0} + {1} hours = {2}", cstTime1.Time, 
                                                    twoAndAHalfHours.ToString(),  
                                                    cstTime2.Time);
      }
      catch
      {
         Console.WriteLine("Unable to find {0}.", tzName);
      }
   }
}

DateTime 値と DateTimeOffset 値はどちらも、どのタイム ゾーンとも関連付けられていません。 タイム ゾーンの調整規則が自動的に適用されるような方法で日付と時刻の演算を実行するには、日時の値の属するタイム ゾーンがすぐに識別できる状態であることが必要です。 つまり、日時とそのタイム ゾーンを密に結合する必要があります。 そのためには、次に示すようにいくつかの方法があります。

  • アプリケーションで使用されるすべての時刻が、特定のタイム ゾーンに属するものと仮定します。 この方法は、適切な場合もありますが、柔軟性が限られ、移植性が制限される可能性もあります。

  • 日時とそのタイム ゾーンを型のフィールドとして組み込むことで、両者を密に結合する型を定義します。 このコード例では、この方法を使用して、日時とタイム ゾーンを 2 つのメンバー フィールドに格納する構造体を定義しています。

この例は、タイム ゾーンの調整規則が結果に適用されるように DateTime 値の算術演算を実行する方法を示しています。 ただし、DateTimeOffset 値も同じように簡単に使用できます。 次の例では、DateTime 値の代わりに DateTimeOffset を使用するように、元の例のコードを適合させる方法を示します。

using System;

public struct TimeZoneTime
{
   public TimeZoneInfo TimeZone;
   public DateTimeOffset Time;

   public TimeZoneTime(TimeZoneInfo tz, DateTimeOffset time)
   {
      if (tz == null) 
         throw new ArgumentNullException("The time zone cannot be a null reference.");

      this.TimeZone = tz;
      this.Time = time;   
   }

   public TimeZoneTime AddTime(TimeSpan interval)
   {
      // Convert time to UTC
      DateTimeOffset utcTime = TimeZoneInfo.ConvertTime(this.Time, TimeZoneInfo.Utc);      
      // Add time interval to time
      utcTime = utcTime.Add(interval);
      // Convert time back to time in time zone
      return new TimeZoneTime(this.TimeZone, TimeZoneInfo.ConvertTime(utcTime, this.TimeZone));
   }
}

public class TimeArithmetic
{
   public const string tzName = "Central Standard Time";

   public static void Main()
   {
      try
      {
         TimeZoneTime cstTime1, cstTime2;

         TimeZoneInfo cst = TimeZoneInfo.FindSystemTimeZoneById(tzName);
         DateTime time1 = new DateTime(2008, 3, 9, 1, 30, 0);          
         TimeSpan twoAndAHalfHours = new TimeSpan(2, 30, 0);

         cstTime1 = new TimeZoneTime(cst, 
                        new DateTimeOffset(time1, cst.GetUtcOffset(time1)));
         cstTime2 = cstTime1.AddTime(twoAndAHalfHours);
         Console.WriteLine("{0} + {1} hours = {2}", cstTime1.Time, 
                                                    twoAndAHalfHours.ToString(),  
                                                    cstTime2.Time);
      }
      catch
      {
         Console.WriteLine("Unable to find {0}.", tzName);
      }
   }
}

最初に UTC に変換せず、単純に DateTimeOffset 値に対してこの加算を実行すると、結果には正しい時刻が反映されますが、その時刻に対して指定されたタイム ゾーンのオフセットは反映されません。

コードのコンパイル

この例には、次の項目が必要です。

  • System.Core.dll への参照をプロジェクトに追加する。

  • System 名前空間を using ステートメントでインポートする (C# のコードで必要)。

表示: