Como: Data de ida e volta e valores de tempo
Em muitos aplicativos, um valor de data e hora destina-se a identificar sem ambiguidade um único ponto no tempo. Este tópico mostra como salvar e restaurar um valor DateTime, um valor DateTimeOffset e um valor de data e hora com informações de fuso horário de modo que o valor restaurado identifique o mesmo horário que o valor salvo.
Para fazer ida e vinda de um valor DateTime
Converta o valor DateTime para sua representação de sequência de caracteres chamando o método DateTime.ToString(String) com o especificador de formato "o".
Salve a representação de sequência de caracteres do valor DateTime para um arquivo, ou passe-o por um processo, domínio de aplicativo ou fronteira de máquina.
Recupere a sequência de caracteres que representa o valor DateTime.
Chame o método DateTime.Parse(String, IFormatProvider, DateTimeStyles) e passe DateTimeStyles.RoundtripKind como o valor do parâmetro styles.
O exemplo a seguir ilustra como fazer ida e vinda de um valor 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.
Ao fazer ide e vinda de um valor DateTime, essa técnica preserva com êxito a hora para todos os horários locais e universais. Por exemplo, se um local DateTime valor é salvo em um sistema nos EUA. Fuso horário oficial do Pacífico e será restaurado em um sistema nos EUA. Zona de hora padrão Central, restaurado de data e hora serão duas horas depois que o tempo original, que reflete a diferença de tempo entre os dois fusos horários. No entanto, essa técnica não é necessariamente exata para horas não especificadas. Todos os valores DateTime cuja propriedade Kind é Unspecified são tratados como se eles fossem horas locais. Se esse não é o caso, o DateTime não identificará com êxito o ponto correto no tempo. A solução para essa limitação é acoplar fortemente um valor de data e hora com o seu fuso horário para a operação de salvar e restaurar.
Para fazer ida e vinda de um valor DateTimeOffset
Converta o valor DateTimeOffset para sua representação de sequência de caracteres chamando o método DateTimeOffset.ToString(String) com o especificador de formato "o".
Salve a representação de sequência de caracteres do valor DateTimeOffset para um arquivo, ou passe-o por um processo, domínio de aplicativo ou fronteira de máquina.
Recupere a sequência de caracteres que representa o valor DateTimeOffset.
Chame o método DateTimeOffset.Parse(String, IFormatProvider, DateTimeStyles) e passe DateTimeStyles.RoundtripKind como o valor do parâmetro styles.
O exemplo a seguir ilustra como fazer ida e vinda de um valor 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.
Essa técnica sempre identifica sem ambiguidade um valor DateTimeOffset como um único ponto no tempo. O valor pode, então, ser convertido para o Tempo Universal Coordenado (UTC) chamando o método DateTimeOffset.ToUniversalTime, ou ele pode ser convertido para a hora em um determinado fuso horário chamando o método DateTimeOffset.ToOffset ou o método TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo). A principal limitação dessa técnica é que a aritmética de data e hora, quando executada em um valor DateTimeOffset que representa a hora em um determinado fuso horário, talvez não produza resultados precisos para esse fuso horário. Isso ocorre porque quando um valor DateTimeOffset é instanciado, ele é dissociado do seu fuso horário. Portanto, regras de ajuste do fuso horário não podem mais ser aplicadas ao executar cálculos de data e hora. Você pode contornar esse problema definindo um tipo personalizado que inclua tanto um valor de data e hora quanto seu respectivo fuso horário.
Para fazer ida e vinda de um valor de data e hora com seu fuso horário
Defina uma classe ou uma estrutura com dois campos. O primeiro campo é um objeto DateTime ou um objeto DateTimeOffset, e o segundo é um objeto TimeZoneInfo. O exemplo a seguir é uma versão simples de tal 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; } } }
Marque a classe com o atributo SerializableAttribute.
Serialize o objeto usando o método BinaryFormatter.Serialize.
Restaure o objeto usando o método Deserialize.
Converta (em C# ou em Visual Basic) o objeto desserializado para um objeto do tipo apropriado.
O exemplo a seguir ilustra como fazer ida e vinda de um objeto que armazena tanto informações de data e hora quanto de fuso horário.
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
Essa técnica deve refletir sempre sem ambiguidade o ponto correto de tempo tanto antes quanto depois de ser salvo e restaurado, desde que a implementação do objeto combinado de data e hora e fuso horário não permita que o valor de data saia de sincronia com o valor de fuso horário.
Compilando o código
Esses exemplos requerem:
Que os seguintes namespaces ser importado com C# using instruções ou Visual Basic Imports instruções:
Uma referência a System.Core.dll.
Cada exemplo de código, que não a classe DateInTimeZone, deve ser incluído em uma classe ou módulo Visual Basic, empacotado em métodos e chamado a partir do método Main.
Consulte também
Conceitos
Executar operações de formatação