Como aplicar uma viagem de ida e volta para valores de data e hora

Em muitos aplicativos, um valor de data e hora destina-se a identificar sem ambiguidade um único ponto no tempo. Este artigo 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 para que o valor restaurado identifique a mesma hora que o valor salvo.

Ida e volta de um valor DateTime

  1. Converta o valor DateTime em sua representação de cadeia de caracteres chamando o método DateTime.ToString(String) com o especificador de formato "o".

  2. Salve a representação de cadeia de caracteres do valor DateTime em um arquivo ou passe-a por um processo, domínio de aplicativo ou limite de computador.

  3. Recupere a cadeia de caracteres que representa o valor DateTime.

  4. Chame o método DateTime.Parse(String, IFormatProvider, DateTimeStyles) e passe DateTimeStyles.RoundtripKind como o valor do parâmetro styles.

O exemplo a seguir mostra como fazer a viagem de ida e volta de um valor 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;

using StreamReader inFile = new StreamReader(fileName);
dateString = inFile.ReadLine();

if (dateString is not null)
{
    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.

Fazendo a viagem de ida e volta de um valor DateTime, essa técnica consegue preservar o horário para todos os horários locais e universais. Por exemplo, se um valor DateTime local for salvo em um sistema no fuso horário padrão do Pacífico dos EUA e for restaurado em um sistema no fuso horário padrão central dos EUA, a data e a hora restauradas serão duas horas depois do horário original , que reflete a diferença horária entre os dois fusos horários. No entanto, essa técnica não é necessariamente exata para horários não especificados. Todos os valores DateTime cuja propriedade Kind é Unspecified são tratados como se fossem horários locais. Se não for uma hora local, o DateTime não identifica com êxito o momento correto. A solução alternativa para essa limitação é acoplar rigorosamente um valor de data e hora com seu fuso horário para salvar e restaurar a operação.

Ida e volta de um valor DateTimeOffset

  1. Converta o valor DateTimeOffset em sua representação de cadeia de caracteres chamando o método DateTimeOffset.ToString(String) com o especificador de formato "o".

  2. Salve a representação de cadeia de caracteres do valor DateTimeOffset em um arquivo ou passe-a por um processo, domínio de aplicativo ou limite de computador.

  3. Recupere a cadeia de caracteres que representa o valor DateTimeOffset.

  4. Chame o método DateTimeOffset.Parse(String, IFormatProvider, DateTimeStyles) e passe DateTimeStyles.RoundtripKind como o valor do parâmetro styles.

O exemplo a seguir mostra como fazer a viagem de ida e volta de um valor 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;

using StreamReader inFile = new StreamReader(fileName);
dateString = inFile.ReadLine();

if (dateString is not null)
{
    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.

Essa técnica sempre identifica sem ambiguidade um valor DateTimeOffset como um único momento. O valor pode ser convertido em UTC (Tempo Universal Coordenado) chamando o método DateTimeOffset.ToUniversalTime ou pode ser convertido em determinado fuso horário chamando o método DateTimeOffset.ToOffset ou 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 o horário em determinado fuso horário, talvez não produza resultados precisos para esse fuso horário. Isso ocorre porque, quando um valor DateTimeOffset é instanciado, é dissociado do fuso horário. Portanto, as regras de ajuste do fuso horário não podem mais ser aplicadas quando você executa cálculos de data e hora. É possível solucionar esse problema definindo um tipo personalizado que inclui um valor de data e hora e o respectivo fuso horário.

Compilar o código

Esses exemplos exigem que os seguintes namespaces podem ser importados com diretivas C# using ou instruções Visual Basic Imports:

Confira também