Instrukcje: Obustronne wartości daty i godziny
W wielu aplikacjach wartość daty i czasu ma na celu jednoznaczną identyfikację pojedynczego punktu w czasie. W tym artykule DateTime pokazano, jak zapisać i przywrócić wartość, DateTimeOffset wartość oraz wartość daty i czasu z informacjami o strefie czasowej, aby przywrócona wartość identyfikuje ten sam czas co zapisana wartość.
Rundy wartości DateTime
Przekonwertuj DateTime wartość na jej reprezentację w postaci ciągu, wywołując DateTime.ToString(String) metodę ze specyfikatorem formatu "o".
Zapisz reprezentację ciągu wartości DateTime w pliku lub przekaż ją przez proces, domenę aplikacji lub granicę maszyny.
Pobierz ciąg reprezentujący wartość DateTime .
Wywołaj DateTime.Parse(String, IFormatProvider, DateTimeStyles) metodę i przekaż DateTimeStyles.RoundtripKind jako wartość parametru
styles
.
W poniższym przykładzie pokazano, jak zaokrąglić wartość DateTime .
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.
W przypadku rundy wartości DateTime ta technika pomyślnie zachowuje czas dla wszystkich czasów lokalnych i uniwersalnych. DateTime Jeśli na przykład wartość lokalna jest zapisywana w systemie w strefie czasowej Pacyfiku Stanów Zjednoczonych i jest przywracana w systemie w strefie czasowej Standardowej Stanów Zjednoczonych, przywrócona data i godzina będą dwie godziny późniejsza niż oryginalny czas, co odzwierciedla różnicę czasu między dwiema strefami czasowymi. Jednak ta technika nie musi być dokładna w przypadku nieokreślonych godzin. Wszystkie DateTime wartości, których Kind właściwość jest Unspecified traktowana tak, jakby były czasem lokalnymi. Jeśli nie jest to czas lokalny, oznacza to, DateTime że punkt w czasie nie jest poprawnie identyfikowany. Obejście tego ograniczenia to ścisłe zesunięcie wartości daty i czasu ze strefą czasową operacji zapisywania i przywracania.
Rundy wartości DateTimeOffset
Przekonwertuj DateTimeOffset wartość na jej reprezentację w postaci ciągu, wywołując DateTimeOffset.ToString(String) metodę ze specyfikatorem formatu "o".
Zapisz reprezentację ciągu wartości DateTimeOffset w pliku lub przekaż ją przez proces, domenę aplikacji lub granicę maszyny.
Pobierz ciąg reprezentujący wartość DateTimeOffset .
Wywołaj DateTimeOffset.Parse(String, IFormatProvider, DateTimeStyles) metodę i przekaż DateTimeStyles.RoundtripKind jako wartość parametru
styles
.
W poniższym przykładzie pokazano, jak zaokrąglić wartość DateTimeOffset .
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.
Ta technika zawsze jednoznacznie identyfikuje DateTimeOffset wartość jako pojedynczy punkt w czasie. Wartość można następnie przekonwertować na wartość Uniwersalny czas koordynowany (UTC) DateTimeOffset.ToUniversalTimeDateTimeOffset.ToOffset przez wywołanie metody lub przekonwertować ją na czas w określonej strefie czasowej przez wywołanie metody lub TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) . Głównym ograniczeniem tej techniki jest to, że arytmetyka daty i czasu wykonywana DateTimeOffset na wartości reprezentującej czas w określonej strefie czasowej może nie dawać dokładnych wyników dla tej strefy czasowej. Jest to spowodowane tym, że DateTimeOffset gdy jest skojarzona wartość, jest ona skojarzona ze swoją strefą czasową. W związku z tym reguły korekty strefy czasowej nie mogą być już stosowane podczas wykonywania obliczeń daty i czasu. Ten problem można rozwiązać, definiując typ niestandardowy, który zawiera zarówno wartość daty i godziny, jak i towarzyszący jej strefę czasową.
Rundy wartości daty i czasu z jej strefą czasową
Zdefiniuj klasę lub strukturę z dwoma polami. Pierwsze pole jest obiektem DateTime lub , a DateTimeOffset drugie obiektem TimeZoneInfo . Poniższy przykład to prosta wersja tego typu.
[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
Oznacz klasę atrybutem SerializableAttribute .
Serializuj obiekt przy użyciu BinaryFormatter.Serialize metody .
Przywróć obiekt przy użyciu Deserialize metody .
Rzutować (w języku C#) lub konwertować (w Visual Basic) zdeserializowany obiekt na obiekt odpowiedniego typu.
Poniższy przykład ilustruje sposób rundy obiektu, który przechowuje zarówno informacje o strefie czasowej, jak i o dacie i godzinie.
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
Ta technika powinna zawsze jednoznacznie odzwierciedlać prawidłowy punkt czasu przed zapisaniem i przywróceniem, pod warunkiem, że implementacja połączonego obiektu daty i godziny i strefy czasowej nie zezwala na synchronizowanie wartości daty z wartością strefy czasowej.
Kompilowanie kodu
Te przykłady wymagają:
Następujące przestrzenie nazw można zaimportować z dyrektywami języka C#
using
lub Visual BasicImports
instrukcje:Każdy przykład kodu, inny
DateInTimeZone
niż klasa, należy do klasy lub modułu Visual Basic, opakowany w metody i wywoływany zMain
metody .