Obtener zona horaria de DateTime

103

¿El .Net DateTime contiene información sobre la zona horaria en la que se creó?

Tengo una biblioteca que analiza DateTime de un formato que tiene "+ zz" al final, y aunque analiza correctamente y ajusta una hora local, necesito obtener cuál era la zona horaria específica del objeto DateTime.

¿Es esto posible en absoluto? Todo lo que puedo ver es DateTime.Kind, que especifica si la hora es local o UTC.

dbkk
fuente
Consulte las notas sobre la documentación de DateTime.Parse para el manejo de zonas horarias y DateTimeStyles. Pero no, lo que quieres no es realmente posible.
yoyo

Respuestas:

136

DateTime en sí no contiene información de zona horaria real. Se puede saber si es UTC o local, pero no lo que realmente significa: locales.

DateTimeOffset es algo mejor, eso es básicamente una hora UTC y un desplazamiento. Sin embargo, eso todavía no es suficiente para determinar la zona horaria, ya que muchas zonas horarias diferentes pueden tener el mismo desplazamiento en cualquier momento. Sin embargo, esto parece que puede ser lo suficientemente bueno para usted, ya que todo lo que tiene que trabajar al analizar la fecha / hora es el desplazamiento.

El soporte para zonas horarias a partir de .NET 3.5 es mucho mejor de lo que era, pero realmente me gustaría ver un "ZonedDateTime" estándar o algo así: una hora UTC y una zona horaria real. Es fácil crear uno propio, pero sería bueno verlo en las bibliotecas estándar.

EDITAR: Casi cuatro años después, ahora sugiero usar Noda Time, que tiene un conjunto bastante más rico de tipos de fecha / hora. Sin embargo, soy parcial, como autor principal de Noda Time :)

Jon Skeet
fuente
2
El proyecto PublicDomain en CodePlex hace esto por usted.
Cheeso
Una enumeración de TimeZone en el BCL sería bueno si las zonas horarias del mundo son estáticas y no cambian.
Jeff LaFay
1
@jlafay: Sin embargo, cambian: se agregaron más zonas horarias a Windows el año pasado, por ejemplo.
Jon Skeet
Este proyecto ya no es mantenido por el autor; publicdomain.codeplex.com Parece que tal vez este pueda ayudar, dependiendo del uso, uno tiene que configurarlo antes de usarlo; timezone.codeplex.com
AnneTheAgile
3
@AnneTheAgile: Personalmente, recomendaría usar mi propia biblioteca Noda Time, por supuesto :)
Jon Skeet
36

No.

Un desarrollador es responsable de realizar un seguimiento de la información de la zona horaria asociada con un valor DateTime a través de algún mecanismo externo.

Una cita de un excelente artículo aquí . Una lectura obligada para todos los desarrolladores de .Net.

Así que mi consejo es escribir una pequeña clase de envoltura que se adapte a sus necesidades.

Gerrie Schenck
fuente
2

Podrías usar la clase TimeZoneInfo

La clase TimeZone reconoce la zona horaria local y puede convertir las horas entre la hora universal coordinada (UTC) y la hora local. Un objeto TimeZoneInfo puede representar cualquier zona horaria, y los métodos de la clase TimeZoneInfo se pueden utilizar para convertir la hora en una zona horaria a la hora correspondiente en cualquier otra zona horaria. Los miembros de la clase TimeZoneInfo admiten las siguientes operaciones:

  1. Recuperar una zona horaria que ya está definida por el sistema operativo.

  2. Enumerar las zonas horarias que están disponibles en un sistema.

  3. Conversión de horas entre diferentes zonas horarias.

  4. Crear una nueva zona horaria que aún no esté definida por el sistema operativo.

    Serializar una zona horaria para su posterior recuperación.

Shekhar
fuente
1
... pero, dado un DateTime, todavía no hay una forma de usar TimeZoneInfo para determinar el TimeZone de DateTime, que yo sepa.
Remi Despres-Smyth
@ RemiDespres-Smyth Acabo de almacenar TimeZoneInfo junto con DateTime en 1 clase.
Konrad
0

Generalmente, la práctica sería pasar datos como un DateTime con una "zona horaria" de UTC y luego pasar un objeto TimeZoneInfo y cuando esté listo para mostrar los datos, use el objeto TimeZoneInfo para convertir el DateTime UTC.

La otra opción es establecer el DateTime con la zona horaria actual, y luego asegurarse de que el "timezone" sea desconocido para el objeto DateTime, luego asegurarse de que DateTime se pase nuevamente con un TimeZoneInfo que indique el TimeZone del DateTime pasado.

Como otros han indicado aquí, sería bueno si Microsoft se hiciera cargo de esto y creara un objeto agradable para hacerlo todo, pero por ahora tienes que lidiar con dos objetos.

Robar
fuente
0

DateTime no conoce su desfase de zona horaria. No hay un método incorporado para devolver el desplazamiento o el nombre de la zona horaria (por ejemplo, EAT, CEST, EST, etc.).

Como lo sugirieron otros, puede convertir su fecha a UTC:

DateTime localtime = new DateTime.Now;
var utctime = localtime.ToUniversalTime();

y luego solo calcula la diferencia:

TimeSpan difference = localtime - utctime;

También puede convertir una vez a otra usando DateTimeOffset:

DateTimeOffset targetTime = DateTimeOffset.Now.ToOffset(new TimeSpan(5, 30, 0));

Pero esto es una especie de compresión con pérdidas: el desplazamiento por sí solo no puede decirle en qué zona horaria es, ya que dos países diferentes pueden estar en diferentes zonas horarias y tener la misma hora solo durante una parte del año (por ejemplo, Sudáfrica y Europa). Además, tenga en cuenta que el horario de verano puede introducirse en diferentes fechas (EST vs CET - una diferencia de 3 semanas).

Puede obtener el nombre de la zona horaria de su sistema local usando la clase TimeZoneInfo:

TimeZoneInfo localZone = TimeZoneInfo.Local;
localZone.IsDaylightSavingTime(localtime) ? localZone.DaylightName : localZone.StandardName

Estoy de acuerdo con Gerrie Schenck, lea el artículo que sugirió.

Henry lagarto
fuente