Gewusst wie: Roundtrip-Datums- und -Uhrzeitwerte
Aktualisiert: November 2007
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
Konvertieren Sie den DateTime-Wert in seine Zeichenfolgedarstellung, indem Sie die DateTime.ToString(String)-Methode mit dem "o"-Formatbezeichner aufrufen.
Speichern Sie die Zeichenfolgedarstellung des DateTime-Werts in eine Datei, oder übergeben Sie sie an einen Prozess, eine Anwendungsdomäne oder einen Computer.
Rufen Sie die Zeichenfolge ab, die den DateTime-Wert darstellt.
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
Konvertieren Sie den DateTimeOffset-Wert in seine Zeichenfolgedarstellung, indem Sie die DateTimeOffset.ToString(String)-Methode mit dem "o"-Formatbezeichner aufrufen.
Speichern Sie die Zeichenfolgedarstellung des DateTimeOffset-Werts in eine Datei, oder übergeben Sie sie an einen Prozess, eine Anwendungsdomäne oder einen Computer.
Rufen Sie die Zeichenfolge ab, die den DateTimeOffset-Wert darstellt.
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
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; } } }
Markieren Sie die Klasse mit dem SerializableAttribute-Attribut.
Serialisieren Sie das Objekt mit der BinaryFormatter.Serialize-Methode.
Stellen Sie das Objekt mit der Deserialize-Methode wieder her.
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:
Dass die folgenden Namespaces mit C#-using-Anweisungen oder Visual BasicImports-Anweisungen importiert werden:
Ein Projektverweis auf System.Core.dll.
Jedes Codebeispiel, mit Ausnahme der DateInTimeZone-Klasse, sollte in eine Klasse oder ein Visual Basic-Modul eingeschlossen werden, in Methoden eingeschlossen werden und von der Main-Methode aufgerufen werden.
Siehe auch
Konzepte
Gewusst-wie-Themen zur Formatierung
Auswählen zwischen "DateTime", "DateTimeOffset" und "TimeZoneInfo"