Partilhar via


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

  1. 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".

  2. 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.

  3. Recupere a sequência 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 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

  1. 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".

  2. 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.

  3. Recupere a sequência 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 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

  1. 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;
          }
       }
    }
    
  2. Marque a classe com o atributo SerializableAttribute.

  3. Serialize o objeto usando o método BinaryFormatter.Serialize.

  4. Restaure o objeto usando o método Deserialize.

  5. 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:

Consulte também

Conceitos

Executar operações de formatação

Escolhendo entre DateTime, DateTimeOffset e TimeZoneInfo

Sequências de caracteres de formato padrão de data e hora