方法: 日付と時刻の値をラウンドトリップさせるHow to: Round-trip Date and Time Values

ある特定の時点を明確に表すように日付と時刻の値を保つことは、多くのアプリケーションに共通する要件です。In many applications, a date and time value is intended to unambiguously identify a single point in time. このトピックでは、DateTime 値、DateTimeOffset 値、日時値と時間帯の情報を保存し、復元する方法について説明します。復元した値によって、保存した値と同じ時刻が識別されるようにします。This topic shows how to save and restore a DateTime value, a DateTimeOffset value, and a date and time value with time zone information so that the restored value identifies the same time as the saved value.

DateTime 値をラウンドトリップさせるにはTo round-trip a DateTime value

  1. DateTime.ToString(String) メソッドを "o" 書式指定子と共に呼び出して、DateTime 値を対応する文字列形式に変換します。Convert the DateTime value to its string representation by calling the DateTime.ToString(String) method with the "o" format specifier.

  2. DateTime 値の文字列形式をファイルに保存するか、プロセス、アプリケーション ドメイン、またはマシン境界を通過させます。Save the string representation of the DateTime value to a file, or pass it across a process, application domain, or machine boundary.

  3. DateTime 値を表す文字列を取得します。Retrieve the string that represents the DateTime value.

  4. DateTime.Parse(String, IFormatProvider, DateTimeStyles) メソッドを呼び出し、styles パラメーターの値として DateTimeStyles.RoundtripKind を渡します。Call the DateTime.Parse(String, IFormatProvider, DateTimeStyles) method, and pass DateTimeStyles.RoundtripKind as the value of the styles parameter.

DateTime 値をラウンドトリップさせる方法を次の例に示します。The following example illustrates how to round-trip a DateTime value.

const string fileName = @".\DateFile.txt";

StreamWriter outFile = new StreamWriter(fileName);

// Save DateTime value.
DateTime dateToSave = DateTime.SpecifyKind(new DateTime(2008, 6, 12, 18, 45, 15), 
                                           DateTimeKind.Local);
string dateString = dateToSave.ToString("o");      
Console.WriteLine("Converted {0} ({1}) to {2}.", 
                  dateToSave.ToString(), 
                  dateToSave.Kind.ToString(), 
                  dateString);      
outFile.WriteLine(dateString);
Console.WriteLine("Wrote {0} to {1}.", dateString, fileName);
outFile.Close();
      
// Restore DateTime value.
DateTime restoredDate;
      
StreamReader inFile = new StreamReader(fileName);
dateString = inFile.ReadLine();
inFile.Close();
restoredDate = DateTime.Parse(dateString, null, DateTimeStyles.RoundtripKind);
Console.WriteLine("Read {0} ({2}) from {1}.", restoredDate.ToString(), 
                                              fileName, 
                                              restoredDate.Kind.ToString());
// The example displays the following output:
//    Converted 6/12/2008 6:45:15 PM (Local) to 2008-06-12T18:45:15.0000000-05:00.
//    Wrote 2008-06-12T18:45:15.0000000-05:00 to .\DateFile.txt.
//    Read 6/12/2008 6:45:15 PM (Local) from .\DateFile.txt.
Const fileName As String = ".\DateFile.txt"

Dim outFile As New StreamWriter(fileName)

' Save DateTime value.
Dim dateToSave As Date = DateTime.SpecifyKind(#06/12/2008 6:45:15 PM#, _
                                              DateTimeKind.Local)
Dim dateString As String = dateToSave.ToString("o")      
Console.WriteLine("Converted {0} ({1}) to {2}.", dateToSave.ToString(), _
                  dateToSave.Kind.ToString(), dateString)      
outFile.WriteLine(dateString)
Console.WriteLine("Wrote {0} to {1}.", dateString, fileName)
outFile.Close()   
      
' Restore DateTime value.
Dim restoredDate As Date
      
Dim inFile As New StreamReader(fileName)
dateString = inFile.ReadLine()
inFile.Close()
restoredDate = DateTime.Parse(dateString, Nothing, DateTimeStyles.RoundTripKind)
Console.WriteLine("Read {0} ({2}) from {1}.", restoredDate.ToString(), _
                  fileName, restoredDAte.Kind.ToString())
' The example displays the following output:
'    Converted 6/12/2008 6:45:15 PM (Local) to 2008-06-12T18:45:15.0000000-05:00.
'    Wrote 2008-06-12T18:45:15.0000000-05:00 to .\DateFile.txt.
'    Read 6/12/2008 6:45:15 PM (Local) from .\DateFile.txt.

DateTime 値をラウンドトリップさせる場合、この方法により、あらゆる現地時刻と協定世界時刻を適切に保存できます。When round-tripping a DateTime value, this technique successfully preserves the time for all local and universal times. たとえば、現地時刻の DateTime 値が米国太平洋標準時タイム ゾーンのシステムで保存され、米国中部標準時タイム ゾーンのシステムで復元された場合、復元された日付と時刻は 2 つのタイム ゾーンの時差を反映し、元の時刻より 2 時間後になります。For example, if a local DateTime value is saved on a system in the U.S. Pacific Standard Time zone and is restored on a system in the U.S. Central Standard Time zone, the restored date and time will be two hours later than the original time, which reflects the time difference between the two time zones. ただし、タイム ゾーンが指定されていない時刻の場合、この方法では必ずしも正確な結果を得られるわけではありません。However, this technique is not necessarily accurate for unspecified times. Kind プロパティが Unspecified であるすべての DateTime 値がローカル時間のように扱われます。All DateTime values whose Kind property is Unspecified are treated as if they are local times. それ以外では、DateTime は間違った時点を示すことになります。If this is not the case, the DateTime will not successfully identify the correct point in time. この制限を回避するには、日付と時刻の値と該当するタイム ゾーンを確実に関連付けてから保存操作と復元操作を行います。The workaround for this limitation is to tightly couple a date and time value with its time zone for the save and restore operation.

DateTimeOffset 値をラウンドトリップさせるにはTo round-trip a DateTimeOffset value

  1. DateTimeOffset.ToString(String) メソッドを "o" 書式指定子と共に呼び出して、DateTimeOffset 値を対応する文字列形式に変換します。Convert the DateTimeOffset value to its string representation by calling the DateTimeOffset.ToString(String) method with the "o" format specifier.

  2. DateTimeOffset 値の文字列形式をファイルに保存するか、プロセス、アプリケーション ドメイン、またはマシン境界を通過させます。Save the string representation of the DateTimeOffset value to a file, or pass it across a process, application domain, or machine boundary.

  3. DateTimeOffset 値を表す文字列を取得します。Retrieve the string that represents the DateTimeOffset value.

  4. DateTimeOffset.Parse(String, IFormatProvider, DateTimeStyles) メソッドを呼び出し、styles パラメーターの値として DateTimeStyles.RoundtripKind を渡します。Call the DateTimeOffset.Parse(String, IFormatProvider, DateTimeStyles) method, and pass DateTimeStyles.RoundtripKind as the value of the styles parameter.

DateTimeOffset 値をラウンドトリップさせる方法を次の例に示します。The following example illustrates how to round-trip a DateTimeOffset value.

const string fileName = @".\DateOff.txt";

StreamWriter outFile = new StreamWriter(fileName);

// Save DateTime value.
DateTimeOffset dateToSave = new DateTimeOffset(2008, 6, 12, 18, 45, 15, 
                                               new TimeSpan(7, 0, 0));
string dateString = dateToSave.ToString("o");      
Console.WriteLine("Converted {0} to {1}.", dateToSave.ToString(), 
                  dateString);      
outFile.WriteLine(dateString);
Console.WriteLine("Wrote {0} to {1}.", dateString, fileName);
outFile.Close();
      
// Restore DateTime value.
DateTimeOffset restoredDateOff;
      
StreamReader inFile = new StreamReader(fileName);
dateString = inFile.ReadLine();
inFile.Close();
restoredDateOff = DateTimeOffset.Parse(dateString, null, 
                                       DateTimeStyles.RoundtripKind);
Console.WriteLine("Read {0} from {1}.", restoredDateOff.ToString(), 
                  fileName);
// The example displays the following output:
//    Converted 6/12/2008 6:45:15 PM +07:00 to 2008-06-12T18:45:15.0000000+07:00.
//    Wrote 2008-06-12T18:45:15.0000000+07:00 to .\DateOff.txt.
//    Read 6/12/2008 6:45:15 PM +07:00 from .\DateOff.txt.
Const fileName As String = ".\DateOff.txt"

Dim outFile As New StreamWriter(fileName)

' Save DateTime value.
Dim dateToSave As New DateTimeOffset(2008, 6, 12, 18, 45, 15, _
                                     New TimeSpan(7, 0, 0))
Dim dateString As String = dateToSave.ToString("o")      
Console.WriteLine("Converted {0} to {1}.", dateToSave.ToString(), dateString)      
outFile.WriteLine(dateString)
Console.WriteLine("Wrote {0} to {1}.", dateString, fileName)
outFile.Close()   
      
' Restore DateTime value.
Dim restoredDateOff As DateTimeOffset
      
Dim inFile As New StreamReader(fileName)
dateString = inFile.ReadLine()
inFile.Close()
restoredDateOff = DateTimeOffset.Parse(dateString, Nothing, DateTimeStyles.RoundTripKind)
Console.WriteLine("Read {0} from {1}.", restoredDateOff.ToString(), fileName)
' The example displays the following output:
'    Converted 6/12/2008 6:45:15 PM +07:00 to 2008-06-12T18:45:15.0000000+07:00.
'    Wrote 2008-06-12T18:45:15.0000000+07:00 to .\DateOff.txt.
'    Read 6/12/2008 6:45:15 PM +07:00 from .\DateOff.txt.

この方法により、DateTimeOffset 値は常にある特定の時点として明確に識別されます。This technique always unambiguously identifies a DateTimeOffset value as a single point in time. 識別されたら、DateTimeOffset.ToUniversalTime メソッドを呼び出すことで、この値を協定世界時 (UTC) に変換できます。あるいは、DateTimeOffset.ToOffset または TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) メソッドを呼び出すことで、特定のタイム ゾーンの時刻に変換できます。The value can then be converted to Coordinated Universal Time (UTC) by calling the DateTimeOffset.ToUniversalTime method, or it can be converted to the time in a particular time zone by calling the DateTimeOffset.ToOffset or TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) method. この方法には、特定のタイム ゾーンの時刻を表す DateTimeOffset 値に対して日付と時刻の演算を行ったときに、そのタイム ゾーンにおける正確な結果を得ることができない場合があるという重要な制限があります。The major limitation of this technique is that date and time arithmetic, when performed on a DateTimeOffset value that represents the time in a particular time zone, may not produce accurate results for that time zone. これは、DateTimeOffset 値をインスタンス化すると、対応するタイム ゾーンとの関連付けが解除されるためです。This is because when a DateTimeOffset value is instantiated, it is disassociated from its time zone. したがって、日付と時刻の計算を実行した場合、タイム ゾーンの調整規則は適用されなくなります。Therefore, that time zone's adjustment rules can no longer be applied when you perform date and time calculations. この問題を回避するには、日付と時刻の値、および付随するタイム ゾーンの両方を保持するカスタム型を定義します。You can work around this problem by defining a custom type that includes both a date and time value and its accompanying time zone.

日時値とそのタイム ゾーンをラウンドトリップするにはTo round-trip a date and time value with its time zone

  1. クラスまたは構造と 2 つのフィールドを定義します。Define a class or a structure with two fields. 最初のフィールドは DateTime または DateTimeOffset オブジェクトです。2 つ目のフィールドは TimeZoneInfo オブジェクトです。The first field is either a DateTime or a DateTimeOffset object, and the second is a TimeZoneInfo object. 次の例は、このような型を簡易にしたものです。The following example is a simple version of such a type.

    [Serializable] public class DateInTimeZone
    {
       private TimeZoneInfo tz;
       private DateTimeOffset thisDate;
       
       public DateInTimeZone() {}
    
       public DateInTimeZone(DateTimeOffset date, TimeZoneInfo timeZone)
       {
          if (timeZone == null) 
             throw new ArgumentNullException("The time zone cannot be null.");
    
          this.thisDate = date;
          this.tz = timeZone;
       }
       
       public DateTimeOffset DateAndTime
       {
          get { 
             return this.thisDate;
          }
          set {
             if (value.Offset != this.tz.GetUtcOffset(value)) 
                this.thisDate = TimeZoneInfo.ConvertTime(value, tz);
             else
                this.thisDate = value;
          }
       }
       
       public TimeZoneInfo TimeZone
       {
          get {
             return this.tz;
          }
       }
    }
    
    <Serializable> Public Class DateInTimeZone
       Private tz As TimeZoneInfo
       Private thisDate As DateTimeOffset
    
       Public Sub New()
       End Sub
          
       Public Sub New(date1 As DateTimeOffset, timeZone As TimeZoneInfo)
          If timeZone Is Nothing Then 
             Throw New ArgumentNullException("The time zone cannot be null.")
          End If
          Me.thisDate = date1
          Me.tz = timeZone
       End Sub
       
       Public Property DateAndTime As DateTimeOffset
          Get
             Return Me.thisDate
          End Get
          Set
             If Value.Offset <> Me.tz.GetUtcOffset(Value) Then
                Me.thisDate = TimeZoneInfo.ConvertTime(Value, tz)
             Else
                Me.thisDate = Value
             End If
          End Set
       End Property
       
       Public ReadOnly Property TimeZone As TimeZoneInfo
          Get
             Return tz
          End Get
       End Property
    End Class
    
  2. クラスに SerializableAttribute 属性を付けます。Mark the class with the SerializableAttribute attribute.

  3. BinaryFormatter.Serialize メソッドを使用し、オブジェクトをシリアル化します。Serialize the object using the BinaryFormatter.Serialize method.

  4. Deserialize メソッドを使用し、オブジェクトを復元します。Restore the object using the Deserialize method.

  5. 逆シリアル化されたオブジェクトを適切な型のオブジェクトにキャスト (C# の場合) するか、変換 (Visual Basic の場合) します。Cast (in C#) or convert (in Visual Basic) the deserialized object to an object of the appropriate type.

次の例では、日時とタイム ゾーン情報の両方を保存するオブジェクトをラウンドトリップする方法を確認できます。The following example illustrates how to round-trip an object that stores both date and time and time zone information.

   const string fileName = @".\DateWithTz.dat";

   DateTime tempDate = new DateTime(2008, 9, 3, 19, 0, 0);
   TimeZoneInfo tempTz = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
   DateInTimeZone dateWithTz = new DateInTimeZone(new DateTimeOffset(tempDate, 
                                   tempTz.GetUtcOffset(tempDate)), 
                                   tempTz);
                                   
   // Store DateInTimeZone value to a file
   FileStream outFile = new FileStream(fileName, FileMode.Create);
   try
   {
      BinaryFormatter formatter = new BinaryFormatter();
      formatter.Serialize(outFile, dateWithTz);
      Console.WriteLine("Saving {0} {1} to {2}", dateWithTz.DateAndTime, 
                        dateWithTz.TimeZone.IsDaylightSavingTime(dateWithTz.DateAndTime) ? 
                        dateWithTz.TimeZone.DaylightName : dateWithTz.TimeZone.DaylightName, 
                        fileName);
   }
   catch (SerializationException)
   {
      Console.WriteLine("Unable to serialize time data to {0}.", fileName);
   }
   finally
   {         
      outFile.Close();
   }

   // Retrieve DateInTimeZone value
   if (File.Exists(fileName))
   {
      FileStream inFile = new FileStream(fileName, FileMode.Open);
      DateInTimeZone dateWithTz2 = new DateInTimeZone();
      try
      {
         BinaryFormatter formatter = new BinaryFormatter();
         dateWithTz2 = formatter.Deserialize(inFile) as DateInTimeZone;   
         Console.WriteLine("Restored {0} {1} from {2}", dateWithTz2.DateAndTime, 
                           dateWithTz2.TimeZone.IsDaylightSavingTime(dateWithTz2.DateAndTime) ? 
                           dateWithTz2.TimeZone.DaylightName : dateWithTz2.TimeZone.DaylightName, 
                           fileName);
      }
      catch (SerializationException)
      {
         Console.WriteLine("Unable to retrieve date and time information from {0}", 
                           fileName);
      }
      finally
      {
         inFile.Close();
      }
   }
   // This example displays the following output to the console:
   //    Saving 9/3/2008 7:00:00 PM -05:00 Central Daylight Time to .\DateWithTz.dat
   //    Restored 9/3/2008 7:00:00 PM -05:00 Central Daylight Time from .\DateWithTz.dat      
Const fileName As String = ".\DateWithTz.dat"

Dim tempDate As Date = #9/3/2008 7:00:00 PM#
Dim tempTz As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")
Dim dateWithTz As New DateInTimeZone(New DateTimeOffset(tempDate, _
                                         tempTz.GetUtcOffset(tempDate)), _
                                     tempTz)

' Store DateInTimeZone value to a file
Dim outFile As New FileStream(fileName, FileMode.Create)
Try
   Dim formatter As New BinaryFormatter()
   formatter.Serialize(outFile, dateWithTz)
   Console.WriteLine("Saving {0} {1} to {2}", dateWithTz.DateAndTime, _
           IIf(dateWithTz.TimeZone.IsDaylightSavingTime(dateWithTz.DateAndTime), _
               dateWithTz.TimeZone.DaylightName, dateWithTz.TimeZone.DaylightName), _
           fileName)
Catch e As SerializationException
   Console.WriteLine("Unable to serialize time data to {0}.", fileName)
Finally   
   outFile.Close()
End Try
            
' Retrieve DateInTimeZone value
If File.Exists(fileName) Then
   Dim inFile As New FileStream(fileName, FileMode.Open)
   Dim dateWithTz2 As New DateInTimeZone()
   Try
      Dim formatter As New BinaryFormatter()
      dateWithTz2 = DirectCast(formatter.Deserialize(inFile), DateInTimeZone)         
      Console.WriteLine("Restored {0} {1} from {2}", dateWithTz2.DateAndTime, _
                        IIf(dateWithTz2.TimeZone.IsDaylightSavingTime(dateWithTz2.DateAndTime), _
                        dateWithTz2.TimeZone.DaylightName, dateWithTz2.TimeZone.DaylightName), _
                        fileName)
   Catch e As SerializationException
      Console.WriteLine("Unable to retrieve date and time information from {0}", _
                        fileName)
   Finally            
      inFile.Close
   End Try
End If
' This example displays the following output to the console:
'    Saving 9/3/2008 7:00:00 PM -05:00 Central Daylight Time to .\DateWithTz.dat
'    Restored 9/3/2008 7:00:00 PM -05:00 Central Daylight Time from .\DateWithTz.dat      

この手法では、日時とタイム ゾーン オブジェクトを組み合わせるとき、日付値とタイム ゾーン値の同期が外れてはならないとき、保存と復元の前後で必ず、常に正しい時点を不明瞭なところなく反映する必要があります。This technique should always unambiguously reflect the correct point of time both before and after it is saved and restored, provided that the implementation of the combined date and time and time zone object does not allow the date value to become out of sync with the time zone value.

コードのコンパイルCompiling the Code

これらの例には次の項目が必要です。These examples require:

関連項目See also