Convertir horas entre zonas horarias

Actualización: noviembre 2007

Cada vez es más importante que las aplicaciones que trabajan con fechas y horas controlen las diferencias entre zonas horarias. Una aplicación ya no puede suponer que todas las horas se pueden expresar en la hora local, que es la hora disponible en la estructura DateTime. Por ejemplo, una página web que muestra la hora actual en la zona oriental de Estados Unidos no tendrá credibilidad para un cliente de Asia oriental. En este tema se explica cómo convertir las horas de una zona horaria a otra, y cómo convertir los valores de DateTimeOffset que tienen un conocimiento limitado de la zona horaria.

Convertir a hora universal coordinada

La hora universal coordinada (UTC) es una norma de hora atómica de gran precisión. Las zonas horarias del mundo se expresan como diferencias positivas o negativas respecto a la hora UTC. Así, la hora UTC proporciona una hora neutra o independiente de la zona horaria. Se recomienda el uso de la hora UTC cuando sea importante la portabilidad de fecha y hora entre equipos. (Para obtener información más detallada y otros procedimientos recomendados sobre el uso de fechas y horas, vea Coding Best Practices Using DateTime in the .NET Framework). La conversión de zonas horarias individuales a horas UTC facilita la comparación de horas.

Nota:

También puede serializar una estructura DateTimeOffset para representar inequívocamente un único punto en el tiempo. Debido a que los objetos DateTimeOffset almacenan un valor de fecha y hora junto con su diferencia respecto a la hora UTC, siempre representan un punto en el tiempo determinado en relación con la hora UTC.

El modo más sencillo de convertir una hora en la hora UTC es llamar al método static (Shared en Visual Basic) TimeZoneInfo.ConvertTimeToUtc(DateTime). La conversión exacta realizada por el método depende del valor de la propiedad Kind del parámetro dateTime, como se muestra en la siguiente tabla.

DateTime.Kind (Propiedad)

Conversión

DateTimeKind.Local

Convierte la hora local en hora UTC.

DateTimeKind.Unspecified

Supone que el parámetro dateTime es la hora local y la convierte en hora UTC.

DateTimeKind.Utc

Devuelve el parámetro dateTime sin modificar.

El código siguiente convierte la hora local actual en hora UTC y muestra el resultado en la consola.

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

El método TimeZoneInfo.ConvertTimeToUtc(DateTime) no genera necesariamente los mismos resultados que los métodos TimeZone.ToUniversalTime y DateTime.ToUniversalTime. Si la zona horaria local del sistema host incluye varias reglas de ajuste, TimeZoneInfo.ConvertTimeToUtc(DateTime) aplica la regla apropiada a un valor de fecha y hora concreto. Los otros dos métodos siempre aplican la última regla de ajuste.

Si el valor de fecha y hora no representa una hora local ni una hora UTC, el método ToUniversalTime devolverá probablemente un resultado erróneo. Sin embargo, puede utilizar el método TimeZoneInfo.ConvertTimeToUtc para convertir el valor de fecha y hora de una zona horaria especificada. (Para obtener información detallada sobre cómo recuperar un objeto TimeZoneInfo que representa la zona horaria de destino, vea Buscar las zonas horarias definidas en un sistema local). El código siguiente utiliza el método TimeZoneInfo.ConvertTimeToUtc para convertir la Hora estándar del Este en hora UTC.

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                           
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 {0} UTC.", 
                     TimeZoneInfo.ConvertTimeToUtc(easternTime, easternZone));
}
catch (TimeZoneNotFoundException)
{
   Console.WriteLine("Unable to find the {0} zone in the registry.", 
                     easternZoneId);
}                           
catch (InvalidTimeZoneException)
{
   Console.WriteLine("Registry data on the {0} zone has been corrupted.", 
                     easternZoneId);
}

Observe que este método produce una excepción ArgumentException si la propiedad Kind del objeto DateTime y la zona horaria no coinciden. Se produce un error de coincidencia si la propiedad Kind es DateTimeKind.Local pero el objeto TimeZoneInfo no representa la zona horaria local, o si la propiedad Kind es DateTimeKind.Utc pero el objeto TimeZoneInfo no es igual a DateTimeKind.Utc.

Todos estos métodos toman valores de DateTime como parámetros y devuelven un valor de DateTime. Para los valores de DateTimeOffset, la estructura DateTimeOffset tiene un método de instancia ToUniversalTime que convierte el valor de fecha y hora de la instancia actual a horario UTC. En el ejemplo siguiente se llama al método ToUniversalTime para convertir una hora local y otras horas a hora universal coordinada (UTC).

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

Convertir una hora UTC a la zona horaria designada

Para convertir una hora UTC en hora local, vea la sección "Convertir una hora UTC en hora local" que sigue a continuación. Para convertir una hora UTC en la hora correspondiente a cualquier zona horaria designada, llame al método ConvertTimeFromUtc. El método toma dos parámetros:

El código siguiente convierte una hora UTC en Hora estándar del Centro.

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
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.");
}

Convertir una hora UTC en hora local

Para convertir una hora UTC en hora local, llame al método ToLocalTime del objeto DateTime cuya hora desea convertir. El comportamiento exacto del método depende del valor de la propiedad Kind del objeto, como muestra la tabla siguiente.

DateTime.Kind (Propiedad)

Conversión

DateTimeKind.Local

Devuelve el valor de DateTime sin modificar.

DateTimeKind.Unspecified

Supone que el valor de DateTime es la hora UTC y la convierte en hora local.

DateTimeKind.Utc

Convierte el valor de DateTime en hora local.

Nota   El método TimeZone.ToLocalTime se comporta de forma idéntica al método DateTime.ToLocalTime. Toma un único parámetro, que es el valor de fecha y hora que se va a convertir.

También puede convertir la hora de cualquier zona horaria designada en hora local utilizando el método TimeZoneInfo.ConvertTimestatic (Shared en Visual Basic). Esta técnica se describe en la sección siguiente.

Convertir entre dos zonas horarias

Puede realizar la conversión entre dos zonas horarias mediante uno de los dos métodos static (Shared en Visual Basic) siguientes de la clase TimeZoneInfo:

  • ConvertTime

    Los parámetros de este método son el valor de fecha y hora que se va a convertir, un objeto TimeZoneInfo que representa la zona horaria del valor de fecha y hora, y un objeto TimeZoneInfo que representa la zona horaria a la que se va a convertir el valor de fecha y hora.

  • ConvertTimeBySystemTimeZoneId

    Los parámetros de este método son el valor de fecha y hora que se va a convertir, el identificador de la zona horaria del valor de fecha y hora, y el identificador de la zona horaria a la que se va a convertir el valor de fecha y hora.

Ambos métodos requieren que la propiedad Kind del valor de fecha y hora que se va a convertir y el objeto TimeZoneInfo o el identificador que representa la zona horaria se correspondan entre sí. De lo contrario, se produce una excepción ArgumentException. Por ejemplo, si la propiedad Kind del valor de fecha y hora es DateTimeKind.Local, se produce una excepción si el objeto TimeZoneInfo pasado como parámetro al método no es igual a TimeZoneInfo.Local. También se produce una excepción si el identificador pasado como parámetro al método no es igual a TimeZoneInfo.Local.Id.

En el ejemplo siguiente se utiliza el método ConvertTime para convertir la Hora estándar de Hawai en hora local.

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                     
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.");
}

Convertir valores de DateTimeOffset

Los valores de fecha y hora representados por objetos DateTimeOffset no tienen totalmente en cuenta la zona horaria porque el objeto no está asociado a su zona horaria en el momento de crearse la instancia. Sin embargo, en muchos casos una aplicación solo necesita convertir un valor de fecha y hora en función de dos diferencias distintas respecto a la hora UTC, en lugar de la hora de las zonas horarias concretas. Para realizar esta conversión, puede llamar al método ToOffset de la instancia actual. El único parámetro del método es la diferencia del nuevo valor de fecha y hora que el método va a devolver.

Por ejemplo, si se conoce el valor de fecha y hora en que un usuario solicita una página web y se serializa como una cadena con el formato MM/dd/aaaa hh:mm:ss zzzz, el método ReturnTimeOnServer siguiente convierte este valor de fecha y hora en el valor de fecha y hora del servidor web.

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
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;
   }
}

Si se pasa al método la cadena "9/1/2007 5:32:07 -05: 00", que representa el valor de fecha y hora en una zona horaria con cinco horas menos que la hora UTC, devuelve "9/1/2007 3:32:07 AM -07: 00" para un servidor situado en la zona horaria estándar del Pacifico de EE.UU.

La clase TimeZoneInfo también incluye una sobrecarga del método TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) que realiza conversiones de zona horaria con valores DateTimeOffset. Los parámetros del método son un valor de DateTimeOffset y una referencia a la zona horaria a la que se va a convertir la hora. La llamada al método devuelve un valor de DateTimeOffset. Por ejemplo, el método ReturnTimeOnServer del ejemplo anterior se puede volver a escribir de la siguiente manera para llamar al método ConvertTime(DateTimeOffset, TimeZoneInfo).

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
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;
   }
}

Vea también

Conceptos

Buscar las zonas horarias definidas en un sistema local

Referencia

TimeZoneInfo

Otros recursos

Horas y zonas horarias