¿Cómo usar TimeZoneInfo para obtener la hora local durante el horario de verano?


84

Estoy tratando de usar DateTimeOffsetpara transmitir un momento específico en el tiempo en cualquier zona horaria. No sé cómo usar TimeZoneInfopara lidiar con el horario de verano.

var dt = DateTime.UtcNow;
Console.WriteLine(dt.ToLocalTime());

var tz = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
var utcOffset = new DateTimeOffset(dt, TimeSpan.Zero);
Console.WriteLine(utcOffset.ToOffset(tz.BaseUtcOffset));

Esto imprime:

2/6/2010 4:37:19 p.m.
2/6/2010 3:37:19 PM -06: 00

Estoy en la zona horaria central y actualmente estamos en el horario de verano. Estoy tratando de leer la segunda línea:

2/6/2010 4:37:19 PM -05: 00

BaseUtcOffset aparentemente no cambia según el horario de verano.

¿Cómo puedo obtener el momento adecuado con el valor de compensación adecuado?


13
+1 - me vuelve loco que TimeZoneInfo.ConvertTimeBySystemTimeZoneId no solo funcione para esto :)
James Manning

@JamesManning: lo hace, suponiendo que dt.Kindesté configurado correctamente.
Matt Johnson-Pint

Respuestas:


61

Necesita obtener el UtcOffset de TimeZoneInfo, luego pasarlo al método ToOffset ():

var dt = DateTime.UtcNow;
Console.WriteLine(dt.ToLocalTime());

var tz = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
var utcOffset = new DateTimeOffset(dt, TimeSpan.Zero);
Console.WriteLine(utcOffset.ToOffset(tz.GetUtcOffset(utcOffset)));

Ya veo ... tienes que obtener la compensación UTC para esa fecha específica en la zona horaria. Gracias.
Jaminto

5
Esta no es la mejor manera en comparación con la respuesta de Karl Gjertsen, que usa una única función .Net para hacer el trabajo en lugar de extraer el desplazamiento mediante la creación de un nuevo desechable DateTimeOffset.
ErikE

59

También puede utilizar TimeZoneInfo.ConvertTimeFromUtc, que permitirá el horario de verano:

DateTime utc = DateTime.UtcNow;
TimeZoneInfo zone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
DateTime localDateTime = TimeZoneInfo.ConvertTimeFromUtc(utc, zone);

¿Qué sucede si la zona horaria de mi país es EEST en verano y EET en invierno? ¿Cómo funcionaría eso con el horario de verano?
Rami Zebian

1
Windows conoce la información de la zona horaria, junto con las fechas del horario de verano. Debería funcionar o usted si elige una de las zonas horarias predefinidas.
Karl Gjertsen

11

O mejor, si no desea codificar el identificador de zona horaria :

TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById(TimeZoneInfo.Local.Id);
DateTime localDateTime = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, tzi);

2
¿No podrías usarlo TimeZoneInfo.Localdirectamente? ¿Por qué necesitas la llamada a FindSystemTimeZoneById?
CoderDennis

4
Tienes razón, no lo necesitamos. Podemos hacerlo asíDateTime localDateTime = TimeZoneInfo.ConvertTimeFromUtc(networkDateTime, TimeZoneInfo.Local);
Pabinator

1
Pero luego está fijado a una única zona horaria. Depende de cómo quieras usar el código, supongo. :-)
Karl Gjertsen

9
Esto no es muy seguro. Si está subcontratando su aplicación a un entorno de nube, no sabe qué zona horaria es local per se.
Tom

5

Soy un principiante tanto en .NET como en stackoverflow, por lo que podría estar equivocado, pero aquí va:

El uso de TimeZoneInfo.ConvertTimeFromUtc permitirá el horario de verano y lo convertirá a la hora correcta de acuerdo con la zona horaria + una posible compensación de DST. Sin embargo, el desplazamiento en sí mismo en el objeto resultante mostrará el desplazamiento de la hora estándar y no tendrá en cuenta el horario de verano. Entonces, si desea hacer un ToString en el objeto, terminará con la hora correcta (en horas y minutos), pero la compensación incorrecta durante el horario de verano, lo que puede llevar al momento equivocado en el tiempo más adelante en el código.

Si, en cambio, usa GetUtcOffset para obtener el desplazamiento para un tiempo específico y luego realiza un ToOffset en el objeto DateTimeOffset, tanto las horas / minutos como el desplazamiento en sí se convertirán correctamente, y puede hacer un ToString de forma segura.

string ExpectedDateTimePattern = "yyyy'-'MM'-'dd'T'HH':'mm':'ss''zzz";
string timeZoneId = "FLE Standard Time";
string dateTimestr = "2017-10-09T09:00:00+02:00";

DateTimeOffset dto = DateTimeOffset.Parse(dateTimeStr);
TimeZoneInfo zone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
TimeSpan offset = zone.GetUtcOffset(dto);
dto = dto.ToOffset(offset);
string localTime = dto.ToString(ExpectedDateTimePattern);

localTime devolverá "2017-10-09T10: 00: 00 + 03: 00".


Según el OP, esta es la respuesta correcta. Lo principal que hay que entender es que UtcOffset para una zona de tiempo no es constante, sino que depende de la fecha misma de la que estamos hablando debido a las reglas de horario de verano . Entonces, el único error que hizo el OP es que usó la constante BaseUtcOffset en lugar de GetUtcOffset (myDate)
g.pickardou
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.