Freigeben über


Gewusst wie: Roundtrip-Datums- und -Uhrzeitwerte

In vielen Anwendungen soll durch einen Datums- und Uhrzeitwert ein bestimmter Zeitpunkt eindeutig identifiziert werden. In diesem Thema wird dargestellt, wie ein DateTime-Wert, ein DateTimeOffset-Wert und ein Datums- und Uhrzeitwert mit Zeitzoneninformationen so gespeichert und wiederhergestellt werden, dass der wiederhergestellte Wert dieselbe Zeit wie der gespeicherte Wert identifiziert.

Herstellen eines Roundtrips für einen DateTime-Wert

  1. Konvertieren Sie den DateTime-Wert in seine Zeichenfolgedarstellung, indem Sie die DateTime.ToString(String)-Methode mit dem "o"-Formatbezeichner aufrufen.

  2. Speichern Sie die Zeichenfolgedarstellung des DateTime-Werts in eine Datei, oder übergeben Sie sie an einen Prozess, eine Anwendungsdomäne oder einen Computer.

  3. Rufen Sie die Zeichenfolge ab, die den DateTime-Wert darstellt.

  4. Rufen Sie die DateTime.Parse(String, IFormatProvider, DateTimeStyles)-Methode auf, und übergeben Sie DateTimeStyles.RoundtripKind als Wert des styles-Parameters.

Das folgende Beispiel zeigt, wie ein Roundtrip für einen DateTime-Wert erstellt wird.

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.
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.

Beim Erstellen eines Roundtrips für einen DateTime-Wert kann mit dieser Technik erfolgreich die Uhrzeit für alle lokalen und Weltzeitangaben beibehalten werden. Wenn beispielsweise ein lokaler DateTime-Wert in einem System in der Zeitzone Pacific Normalzeit gespeichert wird und in einem System in der Zeitzone Central Normalzeit wiederhergestellt wird, so liegen der Datums- und Uhrzeitwert nach der Wiederherstellung zwei Stunden später als die ursprüngliche Zeit, was den Zeitunterschied zwischen diesen beiden Zeitzonen widerspiegelt. Diese Technik ist jedoch nicht notwendigerweise genau für nicht spezifizierte Zeiten. Alle DateTime-Werte, deren Kind-Eigenschaft Unspecified ist, werden als Ortszeiten behandelt. Wenn dies nicht der Fall ist, gibt DateTimenicht erfolgreich den richtigen Zeitpunkt wieder. Diese Einschränkung kann umgangen werden, indem ein Datums- und Zeitwert für den Speicherungs- und Wiederherstellungsvorgang eng mit seiner Zeitzone verknüpft wird.

Herstellen eines Roundtrips für einen DateTimeOffset-Wert

  1. Konvertieren Sie den DateTimeOffset-Wert in seine Zeichenfolgedarstellung, indem Sie die DateTimeOffset.ToString(String)-Methode mit dem "o"-Formatbezeichner aufrufen.

  2. Speichern Sie die Zeichenfolgedarstellung des DateTimeOffset-Werts in eine Datei, oder übergeben Sie sie an einen Prozess, eine Anwendungsdomäne oder einen Computer.

  3. Rufen Sie die Zeichenfolge ab, die den DateTimeOffset-Wert darstellt.

  4. Rufen Sie die DateTimeOffset.Parse(String, IFormatProvider, DateTimeStyles)-Methode auf, und übergeben Sie DateTimeStyles.RoundtripKind als Wert des styles-Parameters.

Das folgende Beispiel zeigt, wie ein Roundtrip für einen DateTimeOffset-Wert erstellt wird.

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.
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.

Mit dieser Technik wird ein DateTimeOffset-Wert stets eindeutig als ein bestimmter Zeitpunkt identifiziert. Der Wert kann dann in die koordinierte Weltzeit (Coordinated Universal Time, UTC) konvertiert werden, indem die DateTimeOffset.ToUniversalTime-Methode aufgerufen wird, oder er kann in die Uhrzeit einer bestimmten Zeitzone konvertiert werden, indem die DateTimeOffset.ToOffset-Methode oder die TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo)-Methode aufgerufen wird. Diese Technik wird im Wesentlichen nur dadurch eingeschränkt, dass die durch die Arithmetik von Datum und Uhrzeit, wenn sie für einen DateTimeOffset-Wert ausgeführt wird, der die Uhrzeit in einer bestimmten Zeitzone darstellt, möglicherweise keine präzisen Ergebnisse für diese Zeitzone erstellt. Das liegt daran, dass beim Instantiieren eines DateTimeOffset-Werts die Zuordnung dieses Werts zu seiner Zeitzone aufgehoben wird. Daher können die Anpassungsregeln dieser Zeitzone nicht mehr angewendet werden, wenn Sie Datums- und Uhrzeitberechnungen durchführen. Sie können dieses Problem umgehen, indem Sie einen benutzerdefinierten Typ definieren, der einen Datums- und einen Uhrzeitwert sowie die dazugehörige Zeitzone umfasst.

So erstellen Sie einen Roundtrip für einen Datums- und Uhrzeitwert mit seiner Zeitzone

  1. Definieren Sie eine Klasse oder eine Struktur mit zwei Feldern. Das erste Feld ist entweder ein DateTime-Objekt oder ein DateTimeOffset-Objekt, und das zweite Feld ist ein TimeZoneInfo-Objekt. Das folgende Beispiel ist die einfache Version eines solchen Typs.

    <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
    
    [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;
          }
       }
    }
    
  2. Markieren Sie die Klasse mit dem SerializableAttribute-Attribut.

  3. Serialisieren Sie das Objekt mit der BinaryFormatter.Serialize-Methode.

  4. Stellen Sie das Objekt mit der Deserialize-Methode wieder her.

  5. Wandeln Sie das deserialisierte Objekt in ein Objekt des richtigen Typs um (in C#) oder konvertieren Sie es (in Visual Basic).

Das folgenden Beispiel veranschaulicht einen Roundtrip für ein Objekt, das Datums- und Uhrzeitinformationen und Zeitzoneninformationen speichert.

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      
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      

Diese Technik sollte immer eindeutig den richtigen Zeitpunkt vor und nach dem Speichern und Wiederherstellen widerspiegeln, unter der Voraussetzung, dass die Implementierung des kombinierten Datums-, Uhrzeit- und Zeitzonen-Objekts es nicht zulässt, dass der Datumswert nicht mehr mit dem Zeitzonenwert synchron ist.

Kompilieren des Codes

Für diese Beispiele gelten folgende Voraussetzungen:

Siehe auch

Konzepte

Durchführen von Formatierungsvorgängen

Auswählen zwischen "DateTime", "DateTimeOffset" und "TimeZoneInfo"

Datums- und Uhrzeitstandardformatzeichenfolgen