Crear un DateTime en un huso horario específico en c #

Intento crear una prueba unitaria para probar el caso cuando la zona horaria cambia en una máquina porque se ha configurado y corregido incorrectamente.

En la prueba, necesito poder crear objetos DateTime en un huso horario no local para garantizar que las personas que ejecutan la prueba puedan hacerlo con éxito, independientemente de dónde se encuentren.

Por lo que puedo ver en el constructor DateTime, puedo configurar TimeZone para que sea la zona horaria local, la zona horaria UTC o no especificada.

¿Cómo creo un DateTime con una zona horaria específica como PST?

La respuesta de Jon habla de TimeZone , pero sugiero usar TimeZoneInfo en su lugar.

Personalmente, me gusta mantener las cosas en UTC siempre que sea posible, así que sugeriría una estructura como esta:

public struct DateTimeWithZone { private readonly DateTime utcDateTime; private readonly TimeZoneInfo timeZone; public DateTimeWithZone(DateTime dateTime, TimeZoneInfo timeZone) { var dateTimeUnspec = DateTime.SpecifyKind(dateTime, DateTimeKind.Unspecified); utcDateTime = TimeZoneInfo.ConvertTimeToUtc(dateTimeUnspec, timeZone); this.timeZone = timeZone; } public DateTime UniversalTime { get { return utcDateTime; } } public TimeZoneInfo TimeZone { get { return timeZone; } } public DateTime LocalTime { get { return TimeZoneInfo.ConvertTime(utcDateTime, timeZone); } } } 

Es posible que desee cambiar los nombres “TimeZone” por “TimeZoneInfo” para aclarar las cosas; prefiero los nombres más breves por mi cuenta.

La estructura DateTimeOffset se creó exactamente para este tipo de uso.

Ver: http://msdn.microsoft.com/en-us/library/system.datetimeoffset.aspx

Aquí hay un ejemplo de cómo crear un objeto DateTimeOffset con una zona horaria específica:

DateTimeOffset do1 = new DateTimeOffset(2008, 8, 22, 1, 0, 0, new TimeSpan(-5, 0, 0));

Las otras respuestas aquí son útiles, pero no cubren cómo acceder específicamente a Pacific, aquí tienes:

 public static DateTime GmtToPacific(DateTime dateTime) { return TimeZoneInfo.ConvertTimeFromUtc(dateTime, TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time")); } 

Por extraño que parezca, aunque “hora estándar del Pacífico” normalmente significa algo diferente de “hora diaria del Pacífico”, en este caso se refiere a la hora del Pacífico en general. De hecho, si usa FindSystemTimeZoneById para recuperarlo, una de las propiedades disponibles es un bool que le dice si esa zona horaria se encuentra actualmente en horario de verano o no.

Puedes ver ejemplos más generalizados de esto en una biblioteca que terminé reuniendo para tratar con DateTimes que necesito en diferentes TimeZones según el lugar donde el usuario pregunta, etc.

https://github.com/b9chris/TimeZoneInfoLib.Net

Esto no funcionará fuera de Windows (por ejemplo, Mono en Linux) ya que la lista de veces proviene del Registro de Windows: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\

Debajo encontrarás claves (icons de carpetas en el Editor del Registro); los nombres de esas claves son lo que pasa a FindSystemTimeZoneById . En Linux, debe usar un conjunto de definiciones de zona horaria estándar de Linux separado, que no he explorado adecuadamente.

Modifiqué que Jon Skeet respondiera un poco por la web con el método de extensión. También funciona en azul como un amuleto.

 public static class DateTimeWithZone { private static readonly TimeZoneInfo timeZone; static DateTimeWithZone() { //I added web.config  //You can add value directly into function. timeZone = TimeZoneInfo.FindSystemTimeZoneById(ConfigurationManager.AppSettings["CurrentTimeZoneId"]); } public static DateTime LocalTime(this DateTime t) { return TimeZoneInfo.ConvertTime(t, timeZone); } } 

Tendrás que crear un objeto personalizado para eso. Su objeto personalizado contendrá dos valores:

  • un valor de DateTime
  • un objeto TimeZone

No estoy seguro de si ya hay un tipo de datos proporcionado por CLR que lo tiene, pero al menos el componente TimeZone ya está disponible.

Me gusta la respuesta de Jon Skeet, pero me gustaría añadir una cosa. No estoy seguro de si Jon esperaba que el controlador siempre se pasara en la zona horaria local. Pero quiero usarlo para los casos en que es algo distinto de lo local.

Estoy leyendo valores de una base de datos, y sé en qué zona horaria se encuentra esa base de datos. Por lo tanto, en el diccionario, pasaré en la zona horaria de la base de datos. Pero luego me gustaría el valor en la hora local. El horario local de Jon no devuelve la fecha original convertida en una fecha de zona horaria local. Devuelve la fecha convertida en la zona horaria original (lo que sea que haya pasado al ctor).

Creo que estos nombres de propiedades lo aclaran …

 public DateTime TimeInOriginalZone { get { return TimeZoneInfo.ConvertTime(utcDateTime, timeZone); } } public DateTime TimeInLocalZone { get { return TimeZoneInfo.ConvertTime(utcDateTime, TimeZoneInfo.Local); } } public DateTime TimeInSpecificZone(TimeZoneInfo tz) { return TimeZoneInfo.ConvertTime(utcDateTime, tz); }