Abreviaturas de zona horaria

TimeZoneInfo no proporciona una abreviatura o un nombre corto para una zona horaria determinada. La única buena manera de hacerlo es tener un diccionario que correlacione abreviaturas con las propiedades Timezone.id , StandardName o DaylightName . Sin embargo, todas las fonts que busqué lista de abreviaturas tienen diferentes nombres de zona horaria, es decir, no es lo mismo que en Windows.

¿Cómo se le muestra al usuario un nombre completo, identificación o cualquier otro nombre en .NET? No quiero el UtcOffset, sino la abreviatura de Zona horaria: PST para Pacífico, UTC, Universal, EST, Eastern Standard, etc. ¿Hay alguna lista o base de datos compatible con C # con todas las zonas horarias posibles y sus abreviaturas compatibles con las que TimeZoneInfo.GetSystemTimeZones() te da?

Este es un requisito difícil, lo mejor que puede hacer es obtener la lista de su elección y crear un método de extensión / ayuda para obtener la abreviatura de TimeZoneInfo.

Una vez que empiezas es en http://www.timeanddate.com/library/abbreviations/timezones/, que tiene una versión de la lista que cubre las zonas que conozco.

El problema sería seleccionar una abreviatura apropiada donde exista más de una para una zona horaria dada. Por ejemplo, UTC puede representarse como UTC o WET (hora de Europa Occidental) o WEZ (Westeuropäische Zeit) o WT (hora estándar de Western Sahara) .

Puede convenir con sus partes interesadas en la convención de nombres que va a seguir con las opciones dadas.

RESPUESTA ACTUALIZADA

Mi respuesta original está debajo, y todavía es válida. Sin embargo, ahora hay una manera más fácil, utilizando la biblioteca TimeZoneNames . Después de instalar desde Nuget , puede hacer lo siguiente:

 string tzid = theTimeZoneInfo.Id; // example: "Eastern Standard time" string lang = CultureInfo.CurrentCulture.Name; // example: "en-US" var abbreviations = TZNames.GetAbbreviationsForTimeZone(tzid, lang); 

El objeto resultante tendrá las propiedades similares a:

 abbreviations.Generic == "ET" abbreviations.Standard == "EST" abbreviations.Daylight == "EDT" 

También puede usar esta misma biblioteca para obtener los nombres completamente localizados de las zonas horarias. La biblioteca utiliza una copia integrada incrustada de los datos CLDR.

RESPUESTA ORIGINAL

Como otros mencionaron, las abreviaturas de zonas horarias son ambiguas. Pero si realmente quiere uno para mostrar, necesita una base de datos de zona horaria de IANA / Olson.

También puede ir desde una zona horaria de Windows a una zona horaria IANA / Olson y en la otra dirección. Pero tenga en cuenta que podría haber múltiples zonas IANA / Olson para cualquier zona de Windows determinada. Estas asignaciones se mantienen en el CLDR aquí .

NodaTime tiene tanto la base de datos como las asignaciones. Puede pasar de .Net DateTime o DateTimeOffset con TimeZoneInfo a NodaTime Instant y DateTimeZone . A partir de ahí, puede obtener el nombre de la abreviatura.

 // starting with a .Net TimeZoneInfo var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"); // You need to resolve to a specific instant in time - a noda Instant // For illustrative purposes, I'll start from a regular .Net UTC DateTime var dateTime = DateTime.UtcNow; var instant = Instant.FromDateTimeUtc(dateTime); // note that if we really wanted to just get the current instant, // it's better and easier to use the following: // var instant = SystemClock.Instance.Now; // Now let's map the Windows time zone to an IANA/Olson time zone, // using the CLDR mappings embedded in NodaTime. This will use // the *primary* mapping from the CLDR - that is, the ones marked // as "territory 001". // we need the NodaTime tzdb source. In NodaTime 1.1.0+: var tzdbSource = TzdbDateTimeZoneSource.Default; // in previous NodaTime releases: // var tzdbSource = new TzdbDateTimeZoneSource("NodaTime.TimeZones.Tzdb"); // map to the appropriate IANA/Olson tzid var tzid = tzdbSource.MapTimeZoneId(timeZoneInfo); // get a DateTimeZone from that id var dateTimeZone = DateTimeZoneProviders.Tzdb[tzid]; // Finally, let's figure out what the abbreviation is // for the instant and zone we have. // now get a ZoneInterval for the zone and the instant var zoneInterval = dateTimeZone.GetZoneInterval(instant); // finally, you can get the correct time zone abbreviation var abbreviation = zoneInterval.Name; // abbreviation will be either PST or PDT depending // on what instant was provided Debug.WriteLine(abbreviation); 

Su pregunta no indica en qué zonas horarias debe operar su aplicación, pero en mi caso particular, solo tengo que preocuparme por las zonas horarias de los Estados Unidos y UTC.

Las abreviaturas de las zonas horarias de EE. UU. Son siempre los primeros caracteres de cada palabra en el nombre de la zona horaria. Por ejemplo, la abreviatura de “Mountain Standard Time” es “MST” y la abreviatura de “Eastern Daylight Time” es “EDT”.

Si tiene requisitos similares, puede derivar fácilmente la abreviatura de la zona horaria local del nombre de la zona horaria local de la siguiente manera (nota: aquí estoy determinando el nombre propio según la fecha y la hora actuales):

 string timeZoneName = TimeZone.CurrentTimeZone.IsDaylightSavingTime(DateTime.Now) ? TimeZone.CurrentTimeZone.DaylightName : TimeZone.CurrentTimeZone.StandardName; string timeZoneAbbrev = GetTzAbbreviation(timeZoneName); 

El código para la función GetTzInitials() es bastante sencillo. Una cosa que vale la pena mencionar es que algunas zonas horarias pueden establecerse en México o Canadá, y los nombres de zona horaria para estos aparecerán con el nombre del país entre paréntesis, como “hora estándar del Pacífico (México)”. Para hacer frente a esto, cualquier información entre paréntesis se devuelve directamente. La abreviatura devuelta para lo anterior será “PST (México)”, que funciona para mí.

 string GetTzAbbreviation(string timeZoneName) { string output = string.Empty; string[] timeZoneWords = timeZoneName.Split(' '); foreach (string timeZoneWord in timeZoneWords) { if (timeZoneWord[0] != '(') { output += timeZoneWord[0]; } else { output += timeZoneWord; } } return output; } 

Aquí hay otro fragmento con NodaTime:

 NodaTime.ZonedDateTime hereAndNow = NodaTime.SystemClock.Instance.Now.InZone( NodaTime.DateTimeZoneProviders.Tzdb.GetSystemDefault()); System.TimeSpan zoneOffset = hereAndNow.ToDateTimeOffset().Offset; string sTimeDisplay = string.Format("{0:G} {1} (UTC{2}{3:hh\\:mm} {4})", hereAndNow.ToDateTimeOffset(), hereAndNow.Zone.GetZoneInterval(hereAndNow.ToInstant()).Name, zoneOffset < TimeSpan.Zero ? "-" : "+", zoneOffset, hereAndNow.Zone.Id); 

En mi sistema esto produce: "4/11/2013 5:03:23 PM CDT (UTC-05: 00 America / Chicago)"

(Gracias a la respuesta de Matt Johnson por la pista de que la abreviatura vive en TimeZoneInterval)

Sería más fácil si NodaTime.ZonedDateTime tuviera un método GetZoneInterval, pero tal vez me falta algo.

Tuve un problema similar, pero no quería usar una biblioteca de terceros (como sugieren la mayoría de estas respuestas). Si solo desea dar soporte a los nombres de la zona horaria de .Net y decide usar una tabla de búsqueda, eche un vistazo a mi respuesta aquí , que se apoya en PHP para ayudar a generar una lista de abreviaturas. Puede adaptar el fragmento allí y la tabla para satisfacer sus necesidades.

Esto es útil para cualquier persona que use Xamarin para iOS o Android porque de acuerdo con la documentación “El nombre para mostrar está localizado en función de la cultura instalada con el sistema operativo Windows”. Al utilizar esto en la zona horaria central, para el DateTime “2016-09-01 12:00:00 GMT”, esta función devuelve “CDT”, que es exactamente lo que necesitaba cuando me encontré con esta pregunta.

 public static string GetTimeZoneAbbreviation(DateTime time) { string timeZoneAbbr; if(time.IsDaylightSavingTime() == true) { timeZoneAbbr = TimeZoneInfo.Local.DaylightName; } else { timeZoneAbbr = TimeZoneInfo.Local.StandardName; } return timeZoneAbbr; }