Partilhar via


Convertendo horários entre fusos horários

Está se tornando cada vez mais importante para qualquer aplicativo que trabalhe com datas e horas lidar com as diferenças entre fusos horários. Um aplicativo não pode mais assumir que todos os horários podem ser expressos na hora local, que é a hora disponível na DateTime estrutura. Por exemplo, uma página da Web que exibe a hora atual na parte oriental dos Estados Unidos não terá credibilidade para um cliente no leste da Ásia. Este artigo explica como converter horários de um fuso horário para outro e converter DateTimeOffset valores que têm reconhecimento de fuso horário limitado.

Conversão para Tempo Universal Coordenado

O Tempo Universal Coordenado (UTC) é um padrão de tempo atômico de alta precisão. Os fusos horários do mundo são expressos como compensações positivas ou negativas do UTC. Assim, o UTC fornece uma hora livre de fuso horário ou uma hora neutra de fuso horário. O uso do UTC é recomendado quando a portabilidade de uma data e hora entre computadores é importante. Para obter detalhes e outras práticas recomendadas usando datas e horas, consulte Práticas recomendadas de codificação usando DateTime no .NET Framework. A conversão de fusos horários individuais em UTC facilita as comparações de horários.

Nota

Você também pode serializar uma DateTimeOffset estrutura para representar um único ponto no tempo de forma inequívoca. Como DateTimeOffset os objetos armazenam um valor de data e hora juntamente com seu deslocamento do UTC, eles sempre representam um ponto específico no tempo em relação ao UTC.

A maneira mais fácil de converter um tempo em UTC é chamar o static método (Shared no Visual Basic TimeZoneInfo.ConvertTimeToUtc(DateTime) ). A conversão exata realizada pelo método depende do valor da propriedade do dateTimeKind parâmetro, como mostra a tabela a seguir:

DateTime.Kind Conversão
DateTimeKind.Local Converte a hora local em UTC.
DateTimeKind.Unspecified Assume que o parâmetro é hora local e converte hora dateTime local para UTC.
DateTimeKind.Utc Retorna o dateTime parâmetro inalterado.

O código a seguir converte a hora local atual em UTC e exibe o resultado no console:

DateTime dateNow = DateTime.Now;
Console.WriteLine($"The date and time are {TimeZoneInfo.ConvertTimeToUtc(dateNow)} UTC.");
Dim dateNow As Date = Date.Now
Console.WriteLine("The date and time are {0} UTC.", _
                  TimeZoneInfo.ConvertTimeToUtc(dateNow))

Se o valor de data e hora não representar a hora local ou UTC, o ToUniversalTime método provavelmente retornará um resultado errado. No entanto, você pode usar o método para converter a data e a hora de um fuso TimeZoneInfo.ConvertTimeToUtc horário especificado. Para obter detalhes sobre como recuperar um TimeZoneInfo objeto que representa o fuso horário de destino, consulte Localizando os fusos horários definidos em um sistema local. O código a seguir usa o método para converter a TimeZoneInfo.ConvertTimeToUtc hora padrão do leste em UTC:

DateTime easternTime = new DateTime(2007, 01, 02, 12, 16, 00);
string easternZoneId = "Eastern Standard Time";
try
{
    TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId);
    Console.WriteLine($"The date and time are {TimeZoneInfo.ConvertTimeToUtc(easternTime, easternZone)} UTC.");
}
catch (TimeZoneNotFoundException)
{
    Console.WriteLine($"Unable to find the {easternZoneId} zone in the registry.");
}
catch (InvalidTimeZoneException)
{
    Console.WriteLine($"Registry data on the {easternZoneId} zone has been corrupted.");
}
Dim easternTime As New Date(2007, 01, 02, 12, 16, 00)
Dim easternZoneId As String = "Eastern Standard Time"
Try
    Dim easternZone As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId)
    Console.WriteLine("The date and time are {0} UTC.", _
                      TimeZoneInfo.ConvertTimeToUtc(easternTime, easternZone))
Catch e As TimeZoneNotFoundException
    Console.WriteLine("Unable to find the {0} zone in the registry.", _
                      easternZoneId)
Catch e As InvalidTimeZoneException
    Console.WriteLine("Registry data on the {0} zone has been corrupted.", _
                      easternZoneId)
End Try

O TimeZoneInfo.ConvertTimeToUtc método lança um ArgumentException se a DateTime propriedade do Kind objeto e o fuso horário são incompatíveis. Uma incompatibilidade ocorre se a Kind propriedade for DateTimeKind.Local mas o TimeZoneInfo objeto não representar o fuso horário local ou se a Kind propriedade for DateTimeKind.Utc mas o TimeZoneInfo objeto não for igual TimeZoneInfo.Utca .

Todos esses métodos tomam DateTime valores como parâmetros e retornam um DateTime valor. Para DateTimeOffset valores, a DateTimeOffset estrutura tem um ToUniversalTime método de instância que converte a data e a hora da instância atual em UTC. O exemplo a seguir chama o ToUniversalTime método para converter uma hora local e várias outras vezes para UTC:

DateTimeOffset localTime, otherTime, universalTime;

// Define local time in local time zone
localTime = new DateTimeOffset(new DateTime(2007, 6, 15, 12, 0, 0));
Console.WriteLine("Local time: {0}", localTime);
Console.WriteLine();

// Convert local time to offset 0 and assign to otherTime
otherTime = localTime.ToOffset(TimeSpan.Zero);
Console.WriteLine("Other time: {0}", otherTime);
Console.WriteLine("{0} = {1}: {2}",
                  localTime, otherTime,
                  localTime.Equals(otherTime));
Console.WriteLine("{0} exactly equals {1}: {2}",
                  localTime, otherTime,
                  localTime.EqualsExact(otherTime));
Console.WriteLine();

// Convert other time to UTC
universalTime = localTime.ToUniversalTime();
Console.WriteLine("Universal time: {0}", universalTime);
Console.WriteLine("{0} = {1}: {2}",
                  otherTime, universalTime,
                  universalTime.Equals(otherTime));
Console.WriteLine("{0} exactly equals {1}: {2}",
                  otherTime, universalTime,
                  universalTime.EqualsExact(otherTime));
Console.WriteLine();
// The example produces the following output to the console:
//    Local time: 6/15/2007 12:00:00 PM -07:00
//
//    Other time: 6/15/2007 7:00:00 PM +00:00
//    6/15/2007 12:00:00 PM -07:00 = 6/15/2007 7:00:00 PM +00:00: True
//    6/15/2007 12:00:00 PM -07:00 exactly equals 6/15/2007 7:00:00 PM +00:00: False
//
//    Universal time: 6/15/2007 7:00:00 PM +00:00
//    6/15/2007 7:00:00 PM +00:00 = 6/15/2007 7:00:00 PM +00:00: True
//    6/15/2007 7:00:00 PM +00:00 exactly equals 6/15/2007 7:00:00 PM +00:00: True
Dim localTime, otherTime, universalTime As DateTimeOffset

' Define local time in local time zone
localTime = New DateTimeOffset(#6/15/2007 12:00:00PM#)
Console.WriteLine("Local time: {0}", localTime)
Console.WriteLine()

' Convert local time to offset 0 and assign to otherTime
otherTime = localTime.ToOffset(TimeSpan.Zero)
Console.WriteLine("Other time: {0}", otherTime)
Console.WriteLine("{0} = {1}: {2}", _
                  localTime, otherTime, _
                  localTime.Equals(otherTime))
Console.WriteLine("{0} exactly equals {1}: {2}", _
                  localTime, otherTime, _
                  localTime.EqualsExact(otherTime))
Console.WriteLine()

' Convert other time to UTC
universalTime = localTime.ToUniversalTime()
Console.WriteLine("Universal time: {0}", universalTime)
Console.WriteLine("{0} = {1}: {2}", _
                  otherTime, universalTime, _
                  universalTime.Equals(otherTime))
Console.WriteLine("{0} exactly equals {1}: {2}", _
                  otherTime, universalTime, _
                  universalTime.EqualsExact(otherTime))
Console.WriteLine()
' The example produces the following output to the console:
'    Local time: 6/15/2007 12:00:00 PM -07:00
'    
'    Other time: 6/15/2007 7:00:00 PM +00:00
'    6/15/2007 12:00:00 PM -07:00 = 6/15/2007 7:00:00 PM +00:00: True
'    6/15/2007 12:00:00 PM -07:00 exactly equals 6/15/2007 7:00:00 PM +00:00: False
'    
'    Universal time: 6/15/2007 7:00:00 PM +00:00
'    6/15/2007 7:00:00 PM +00:00 = 6/15/2007 7:00:00 PM +00:00: True
'    6/15/2007 7:00:00 PM +00:00 exactly equals 6/15/2007 7:00:00 PM +00:00: True   

Convertendo UTC em um fuso horário designado

Para converter UTC para hora local, consulte a seção Convertendo UTC para hora local a seguir. Para converter UTC para a hora em qualquer fuso horário que você designar, chame o ConvertTimeFromUtc método. O método usa dois parâmetros:

  • O UTC para converter. Este deve ser um DateTime valor cuja Kind propriedade está definida como Unspecified ou Utc.

  • O fuso horário para converter o UTC.

O código a seguir converte UTC para Hora Padrão Central:

DateTime timeUtc = DateTime.UtcNow;
try
{
    TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
    DateTime cstTime = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, cstZone);
    Console.WriteLine("The date and time are {0} {1}.",
                      cstTime,
                      cstZone.IsDaylightSavingTime(cstTime) ?
                              cstZone.DaylightName : cstZone.StandardName);
}
catch (TimeZoneNotFoundException)
{
    Console.WriteLine("The registry does not define the Central Standard Time zone.");
}
catch (InvalidTimeZoneException)
{
    Console.WriteLine("Registry data on the Central Standard Time zone has been corrupted.");
}
Dim timeUtc As Date = Date.UtcNow
Try
    Dim cstZone As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")
    Dim cstTime As Date = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, cstZone)
    Console.WriteLine("The date and time are {0} {1}.", _
                      cstTime, _
                      IIf(cstZone.IsDaylightSavingTime(cstTime), _
                          cstZone.DaylightName, cstZone.StandardName))
Catch e As TimeZoneNotFoundException
    Console.WriteLine("The registry does not define the Central Standard Time zone.")
Catch e As InvalidTimeZoneException
    Console.WriteLine("Registry data on the Central Standard Time zone has been corrupted.")
End Try

Convertendo UTC para hora local

Para converter UTC em hora local, chame o ToLocalTimeDateTime método do objeto cuja hora você deseja converter. O comportamento exato do método depende do valor da propriedade do Kind objeto, como mostra a tabela a seguir:

DateTime.Kind Conversão
DateTimeKind.Local Devolve o DateTime valor inalterado.
DateTimeKind.Unspecified Assume que o DateTime valor é UTC e converte o UTC para a hora local.
DateTimeKind.Utc Converte o valor para a DateTime hora local.

Nota

O TimeZone.ToLocalTime método comporta-se de forma idêntica ao DateTime.ToLocalTime método. É necessário um único parâmetro, que é o valor de data e hora, para converter.

Você também pode converter a hora em qualquer fuso horário designado para a hora local usando o static método (Shared no Visual Basic TimeZoneInfo.ConvertTime ). Esta técnica é discutida na próxima seção.

Conversão entre dois fusos horários

Você pode converter entre quaisquer dois fusos TimeZoneInfo horários usando um dos seguintes dois static (Sharedno Visual Basic) métodos da classe:

  • ConvertTime

    Os parâmetros desse método são o valor de data e hora a ser convertido, um TimeZoneInfo objeto que representa o fuso horário do valor de data e hora e um TimeZoneInfo objeto que representa o fuso horário para converter o valor de data e hora.

  • ConvertTimeBySystemTimeZoneId

    Os parâmetros deste método são o valor de data e hora a converter, o identificador do fuso horário do valor de data e hora e o identificador do fuso horário para converter o valor de data e hora.

Ambos os métodos exigem que a Kind propriedade do valor de data e hora a converter e o identificador de objeto ou fuso TimeZoneInfo horário que representa seu fuso horário correspondam um ao outro. Caso contrário, um ArgumentException é jogado. Por exemplo, se a Kind propriedade do valor de data e hora for DateTimeKind.Local, uma exceção será lançada se o TimeZoneInfo objeto passado como parâmetro para o método não for igual a TimeZoneInfo.Local. Uma exceção também será lançada se o identificador passado como parâmetro para o método não for igual a TimeZoneInfo.Local.Id.

O exemplo a seguir usa o método para converter da hora padrão havaiana para a ConvertTime hora local:

DateTime hwTime = new DateTime(2007, 02, 01, 08, 00, 00);
try
{
    TimeZoneInfo hwZone = TimeZoneInfo.FindSystemTimeZoneById("Hawaiian Standard Time");
    Console.WriteLine("{0} {1} is {2} local time.",
            hwTime,
            hwZone.IsDaylightSavingTime(hwTime) ? hwZone.DaylightName : hwZone.StandardName,
            TimeZoneInfo.ConvertTime(hwTime, hwZone, TimeZoneInfo.Local));
}
catch (TimeZoneNotFoundException)
{
    Console.WriteLine("The registry does not define the Hawaiian Standard Time zone.");
}
catch (InvalidTimeZoneException)
{
    Console.WriteLine("Registry data on the Hawaiian Standard Time zone has been corrupted.");
}
Dim hwTime As Date = #2/01/2007 8:00:00 AM#
Try
    Dim hwZone As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Hawaiian Standard Time")
    Console.WriteLine("{0} {1} is {2} local time.", _
                      hwTime, _
                      IIf(hwZone.IsDaylightSavingTime(hwTime), hwZone.DaylightName, hwZone.StandardName), _
                      TimeZoneInfo.ConvertTime(hwTime, hwZone, TimeZoneInfo.Local))
Catch e As TimeZoneNotFoundException
    Console.WriteLine("The registry does not define the Hawaiian Standard Time zone.")
Catch e As InvalidTimeZoneException
    Console.WriteLine("Registry data on the Hawaiian Standard Time zone has been corrupted.")
End Try

Convertendo valores DateTimeOffset

Os valores de data e hora representados por DateTimeOffset objetos não reconhecem totalmente o fuso horário porque o objeto é dissociado de seu fuso horário no momento em que é instanciado. No entanto, em muitos casos, um aplicativo simplesmente precisa converter uma data e hora com base em dois deslocamentos diferentes do UTC em vez de na hora em fusos horários específicos. Para executar essa conversão, você pode chamar o método da ToOffset instância atual. O único parâmetro do método é o deslocamento do novo valor de data e hora que o método retornará.

Por exemplo, se a data e a hora de uma solicitação de usuário para uma página da Web for conhecida e for serializada como uma cadeia de caracteres no formato MM/dd/aa hh:mm:ss zzzz, o método a seguir ReturnTimeOnServer converte esse valor de data e hora para a data e hora no servidor Web:

public DateTimeOffset ReturnTimeOnServer(string clientString)
{
   string format = @"M/d/yyyy H:m:s zzz";
   TimeSpan serverOffset = TimeZoneInfo.Local.GetUtcOffset(DateTimeOffset.Now);

   try
   {
      DateTimeOffset clientTime = DateTimeOffset.ParseExact(clientString, format, CultureInfo.InvariantCulture);
      DateTimeOffset serverTime = clientTime.ToOffset(serverOffset);
      return serverTime;
   }
   catch (FormatException)
   {
      return DateTimeOffset.MinValue;
   }
}
Public Function ReturnTimeOnServer(clientString As String) As DateTimeOffset
    Dim format As String = "M/d/yyyy H:m:s zzz"
    Dim serverOffset As TimeSpan = TimeZoneInfo.Local.GetUtcOffset(DateTimeOffset.Now)

    Try
        Dim clientTime As DateTimeOffset = DateTimeOffset.ParseExact(clientString, format, CultureInfo.InvariantCulture)
        Dim serverTime As DateTimeOffset = clientTime.ToOffset(serverOffset)
        Return serverTime
    Catch e As FormatException
        Return DateTimeOffset.MinValue
    End Try
End Function

Se o método passar a string "9/1/2007 5:32:07 -05:00," que representa a data e a hora em um fuso horário cinco horas antes do UTC, ele retornará "9/1/2007 3:32:07 AM -07:00" para um servidor localizado no fuso horário padrão do Pacífico dos EUA.

A TimeZoneInfo classe também inclui uma sobrecarga do método que executa conversões de fuso TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) horário com ToOffset(TimeSpan) valores. Os parâmetros do método são um DateTimeOffset valor e uma referência ao fuso horário para o qual a hora deve ser convertida. A chamada de método retorna um DateTimeOffset valor. Por exemplo, o ReturnTimeOnServer método no exemplo anterior pode ser reescrito da seguinte forma para chamar o ConvertTime(DateTimeOffset, TimeZoneInfo) método.

public DateTimeOffset ReturnTimeOnServer(string clientString)
{
   string format = @"M/d/yyyy H:m:s zzz";

   try
   {
      DateTimeOffset clientTime = DateTimeOffset.ParseExact(clientString, format,
                                  CultureInfo.InvariantCulture);
      DateTimeOffset serverTime = TimeZoneInfo.ConvertTime(clientTime,
                                  TimeZoneInfo.Local);
      return serverTime;
   }
   catch (FormatException)
   {
      return DateTimeOffset.MinValue;
   }
}
Public Function ReturnTimeOnServer(clientString As String) As DateTimeOffset
    Dim format As String = "M/d/yyyy H:m:s zzz"

    Try
        Dim clientTime As DateTimeOffset = DateTimeOffset.ParseExact(clientString, format, CultureInfo.InvariantCulture)
        Dim serverTime As DateTimeOffset = TimeZoneInfo.ConvertTime(clientTime, TimeZoneInfo.Local)
        Return serverTime
    Catch e As FormatException
        Return DateTimeOffset.MinValue
    End Try
End Function

Consulte também