Para ver el artículo en inglés, active la casilla Inglés. También puede ver el texto en inglés en una ventana emergente si pasa el puntero del mouse por el texto.
Traducción
Inglés

Convertir horas entre zonas horarias

 

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.

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 detallada y otros procedimientos recomendados con las fechas y horas, vea Procedimientos recomendados Utilizar DateTime de codificación en .NET Framework.) La conversión de zonas horarias individuales a horas UTC facilita la comparación de horas.

System_CAPS_noteNota

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.

Propiedad DateTime.Kind

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.

DateTime dateNow = DateTime.Now;
Console.WriteLine("The date and time are {0} UTC.", 
                   TimeZoneInfo.ConvertTimeToUtc(dateNow));
System_CAPS_noteNota

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.

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

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   

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.

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

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.

Propiedad DateTime.Kind

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.

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.

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

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 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 el método se pasa la cadena “9/1/2007 5:32: 07 -05:00”, que representa la fecha y hora de una zona horaria cinco horas de anterior a la hora UTC, devuelve 9/1/2007 3:32: 07 -07:00 De la para un servidor ubicado en la zona horaria estándar del Pacífico 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 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;
   }
}
Mostrar: