Procedura: Eseguire il round trip dei valori di data e oraHow to: Round-trip Date and Time Values

In molte applicazioni un valore di data e ora deve identificare una data e un'ora singole in modo non ambiguo.In many applications, a date and time value is intended to unambiguously identify a single point in time. Questo argomento illustra come salvare e ripristinare un valore DateTime, un valore DateTimeOffset e un valore di data e ora con informazioni sul fuso orario, in modo che il valore ripristinato identifichi la stessa ora del valore salvato.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.

Per eseguire il round trip di un valore DateTimeTo round-trip a DateTime value

  1. Convertire il valore DateTime nella relativa rappresentazione di stringa chiamando il metodo DateTime.ToString(String) con l'identificatore di formato "o".Convert the DateTime value to its string representation by calling the DateTime.ToString(String) method with the "o" format specifier.

  2. Salvare la rappresentazione di stringa del valore DateTime in un file o passarla attraverso un processo, un dominio dell'applicazione o un limite della macchina.Save the string representation of the DateTime value to a file, or pass it across a process, application domain, or machine boundary.

  3. Recuperare la stringa che rappresenta il valore DateTime.Retrieve the string that represents the DateTime value.

  4. Chiamare il metodo DateTime.Parse(String, IFormatProvider, DateTimeStyles) e passare DateTimeStyles.RoundtripKind come valore del parametro styles.Call the DateTime.Parse(String, IFormatProvider, DateTimeStyles) method, and pass DateTimeStyles.RoundtripKind as the value of the styles parameter.

L'esempio seguente illustra come eseguire il round trip di un valore 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.

Quando si esegue il round trip di un valore DateTime, questa tecnica consente di mantenere correttamente l'ora per tutte le ore locali e UTC.When round-tripping a DateTime value, this technique successfully preserves the time for all local and universal times. Se, ad esempio, un valore DateTime locale viene salvato in un sistema con fuso orario ora solare pacifico e viene ripristinato in un sistema con fuso orario ora solare centrale, la data e l'ora ripristinate saranno due ore avanti rispetto all'orario originale. Ciò riflette la differenza tra i due fusi orari.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. Tuttavia, questa tecnica non è sempre accurata per le ore non specificate.However, this technique is not necessarily accurate for unspecified times. Tutti i valori DateTime la cui proprietà Kind è Unspecified vengono trattati come valori di ora locale.All DateTime values whose Kind property is Unspecified are treated as if they are local times. Se ciò non avvenisse, DateTime non potrebbe identificare il punto nel tempo corretto.If this is not the case, the DateTime will not successfully identify the correct point in time. La soluzione alternativa per questa limitazione consiste nell'associare un valore di data e ora al proprio fuso orario per l'operazione di salvataggio e ripristino.The workaround for this limitation is to tightly couple a date and time value with its time zone for the save and restore operation.

Per eseguire il round trip di un valore DateTimeOffsetTo round-trip a DateTimeOffset value

  1. Convertire il valore DateTimeOffset nella relativa rappresentazione di stringa chiamando il metodo DateTimeOffset.ToString(String) con l'identificatore di formato "o".Convert the DateTimeOffset value to its string representation by calling the DateTimeOffset.ToString(String) method with the "o" format specifier.

  2. Salvare la rappresentazione di stringa del valore DateTimeOffset in un file o passarla attraverso un processo, un dominio dell'applicazione o un limite della macchina.Save the string representation of the DateTimeOffset value to a file, or pass it across a process, application domain, or machine boundary.

  3. Recuperare la stringa che rappresenta il valore DateTimeOffset.Retrieve the string that represents the DateTimeOffset value.

  4. Chiamare il metodo DateTimeOffset.Parse(String, IFormatProvider, DateTimeStyles) e passare DateTimeStyles.RoundtripKind come valore del parametro styles.Call the DateTimeOffset.Parse(String, IFormatProvider, DateTimeStyles) method, and pass DateTimeStyles.RoundtripKind as the value of the styles parameter.

L'esempio seguente illustra come eseguire il round trip di un valore 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.

Questa tecnica consente sempre di identificare in modo non ambiguo il valore DateTimeOffset come singolo punto nel tempo.This technique always unambiguously identifies a DateTimeOffset value as a single point in time. Il valore può quindi essere convertito nell'ora UTC (Coordinated Universal Time) chiamando il metodo DateTimeOffset.ToUniversalTime oppure può essere convertito nell'ora di un particolare fuso orario chiamando il metodo DateTimeOffset.ToOffset o 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. La limitazione principale di questa tecnica è che le operazioni aritmetiche con data e ora, quando eseguite su un valore DateTimeOffset che rappresenta l'ora di un particolare fuso orario, possono restituire risultati non precisi per quel fuso orario.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. Ciò si verifica perché quando viene creata un'istanza di un valore DateTimeOffset, viene rimossa l'associazione del valore dal relativo fuso orario.This is because when a DateTimeOffset value is instantiated, it is disassociated from its time zone. Di conseguenza, le regole di rettifica del fuso orario non possono più essere applicate quando si eseguono i calcoli di data e ora.Therefore, that time zone's adjustment rules can no longer be applied when you perform date and time calculations. È possibile risolvere questo problema mediante la definizione di un tipo personalizzato che includa sia un valore di data e ora sia il fuso orario ad esso associato.You can work around this problem by defining a custom type that includes both a date and time value and its accompanying time zone.

Per il round trip a un valore di data e ora con il proprio fuso orarioTo round-trip a date and time value with its time zone

  1. Definire una classe o una struttura con due campi.Define a class or a structure with two fields. Il primo campo è un oggetto DateTime o DateTimeOffset e il secondo è un oggetto TimeZoneInfo.The first field is either a DateTime or a DateTimeOffset object, and the second is a TimeZoneInfo object. L'esempio seguente è una versione semplificata di tale tipo.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. Contrassegnare la classe con l'attributo SerializableAttribute.Mark the class with the SerializableAttribute attribute.

  3. Serializzare l'oggetto usando il metodo BinaryFormatter.Serialize.Serialize the object using the BinaryFormatter.Serialize method.

  4. Ripristinare l'oggetto usando il metodo Deserialize.Restore the object using the Deserialize method.

  5. Eseguire il cast (in C#) o la conversione (in Visual Basic) dell'oggetto deserializzato in un oggetto del tipo appropriato.Cast (in C#) or convert (in Visual Basic) the deserialized object to an object of the appropriate type.

L'esempio seguente illustra come eseguire un round trip di un oggetto che archivia informazioni relative sia a data e ora che al fuso orario.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      

Questa tecnica riflette sempre senza ambiguità il punto nel tempo corretto prima e dopo il salvataggio e il ripristino, a condizione che l'implementazione dell'oggetto combinato di data e ora e fuso orario non consenta al valore di data di perdere la sincronizzazione con il valore di fuso orario.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.

Compilazione del codiceCompiling the Code

Gli esempi presentano i requisiti seguenti:These examples require:

Vedere ancheSee Also

Esecuzione di operazioni di formattazionePerforming Formatting Operations
Scelta tra DateTime, DateTimeOffset, TimeSpan e TimeZoneInfoChoosing Between DateTime, DateTimeOffset, TimeSpan, and TimeZoneInfo
Stringhe di formato di data e ora standardStandard Date and Time Format Strings