Procedura: eseguire una sequenza di andata e ritorno dei valori di data e ora
In molte applicazioni un valore di data e ora consente di identificare in modo inequivocabile uno specifico determinato momento. In questo argomento viene illustrato 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.
Per eseguire una sequenza di andata e ritorno di un valore DateTime
Convertire il valore DateTime nella relativa rappresentazione di stringa chiamando il metodo DateTime.ToString(String) con l'identificatore di formato "o".
Salvare la rappresentazione di stringa del valore DateTime in un file o passarla a un processo, un dominio applicazione o all'esterno del computer.
Recuperare la stringa che rappresenta il valore DateTime.
Chiamare il metodo DateTime.Parse(String, IFormatProvider, DateTimeStyles) e passare DateTimeStyles.RoundtripKind come valore del parametro styles.
Nell'esempio di codice seguente viene descritto come eseguire una sequenza di andata e ritorno di un valore DateTime.
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.
Quando si esegue una sequenza di andata e ritorno di un valore DateTime, questa tecnica consente di mantenere correttamente l'ora per tutte le ore locali e universali. Ad esempio, se un valore locale DateTime viene salvato su un sistema nel fuso orario Ora solare Pacifico (Stati Uniti) e viene ripristinato su un sistema nel fuso orario Ora solare fuso centrale (Stati Uniti), la data e l'ora ripristinate saranno in ritardo di due ore rispetto all'ora originale, che corrisponde alla differenza di ora tra i due fusi orari. Questa tecnica non è tuttavia necessariamente accurata per le ore non specificate. Tutti i valori DateTime la cui proprietà Kind è Unspecified vengono gestiti come ore locali. In caso contrario, DateTime non identificherà correttamente il momento esatto. La soluzione alternativa per questa limitazione consiste nell'associare strettamente un valore di data e ora con il fuso orario l'operazione di salvataggio e ripristino.
Per eseguire una sequenza di andata e ritorno di un valore DateTimeOffset
Convertire il valore DateTimeOffset nella relativa rappresentazione di stringa chiamando il metodo DateTimeOffset.ToString(String) con l'identificatore di formato "o".
Salvare la rappresentazione di stringa del valore DateTimeOffset in un file o passarla a un processo, un dominio applicazione o all'esterno del computer.
Recuperare la stringa che rappresenta il valore DateTimeOffset.
Chiamare il metodo DateTimeOffset.Parse(String, IFormatProvider, DateTimeStyles) e passare DateTimeStyles.RoundtripKind come valore del parametro styles.
Nell'esempio di codice seguente viene descritto come eseguire una sequenza di andata e ritorno di un valore DateTimeOffset.
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.
Questa tecnica consente di identificare sempre in modo inequivocabile un valore DateTimeOffset come uno specifico momento. Il valore può quindi essere convertito in 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). La limitazione principale di questa tecnica è la possibilità che le operazioni aritmetiche con date e ore, quando vengono eseguite su un valore DateTimeOffset che rappresenta l'ora un particolare fuso orario, non producano risultati accurati per quel fuso orario. Ciò è dovuto al fatto che quando si crea un'istanza di un valore DateTimeOffset, viene annullata l'associazione con il relativo fuso orario. Pertanto, le regole di rettifica di un fuso orario non possono più essere applicate quando si eseguono calcoli di data e ora. Per risolvere questo problema, è possibile definire un tipo personalizzato che includa un valore di data e ora e il fuso orario associato.
Per eseguire una sequenza di andata e ritorno di un valore di data e ora con il relativo fuso orario
Definire una classe o una struttura con due campi. Il primo campo è un oggetto DateTime o DateTimeOffset, mentre il secondo è un oggetto TimeZoneInfo. Di seguito è riportato l'esempio di una semplice versione di tale tipo.
<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; } } }
Contrassegnare la classe con l'attributo SerializableAttribute.
Serializzare l'oggetto utilizzando il metodo BinaryFormatter.Serialize.
Ripristinare l'oggetto utilizzando il metodo Deserialize.
Eseguire il cast (in C#) o convertire (in Visual Basic) l'oggetto deserializzato in un oggetto del tipo adatto.
Nell'esempio seguente viene illustrato come eseguire una sequenza di andata e ritorno di un oggetto in cui sono archiviati sia la data e l'ora che le informazioni sul fuso orario.
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
Questa tecnica deve riflettere sempre in modo inequivocabile il momento esatto sia prima che dopo le operazioni di salvataggio e ripristino, a condizione che l'implementazione dell'oggetto data e ora e fuso orario combinato non consenta al valore relativo alla data di perdere la sincronizzazione con il valore del fuso orario.
Compilazione del codice
Requisiti:
Gli spazi dei nomi seguenti devono essere importati con istruzioni C# using o istruzioni Visual Basic Imports:
Riferimento a System.Core.dll.
Ogni esempio di codice, tranne la classe DateInTimeZone, deve essere incluso in una classe o un modulo di Visual Basic, incapsulato nei metodi e chiamato dal metodo Main.
Vedere anche
Concetti
Esecuzione di operazioni di formattazione