¿Cómo debería completar una lista de husos horarios de IANA / Olson desde Noda Time?

Estoy usando NodaTime en una aplicación, y necesito que el usuario seleccione su zona horaria de una lista desplegable. Tengo los siguientes requisitos blandos:

1) La lista solo contiene opciones que son razonablemente válidas para el presente y el futuro cercano para lugares reales. Las zonas horarias históricas, oscuras y genéricas deben filtrarse.

2) La lista debe ordenarse primero por desplazamiento UTC, y luego por nombre de zona horaria. Es de esperar que los ponga en un orden que sea significativo para el usuario.

He escrito el siguiente código, que de hecho funciona, pero no tiene exactamente lo que busco. Es probable que el filtro deba ajustarse, y prefiero que el desplazamiento represente el desplazamiento base (sin dst), en lugar del desplazamiento actual.

Sugerencias? Recomendaciones?

var now = Instant.FromDateTimeUtc(DateTime.UtcNow); var tzdb = DateTimeZoneProviders.Tzdb; var list = from id in tzdb.Ids where id.Contains("/") && !id.StartsWith("etc", StringComparison.OrdinalIgnoreCase) let tz = tzdb[id] let offset = tz.GetOffsetFromUtc(now) orderby offset, id select new { Id = id, DisplayValue = string.Format("({0}) {1}", offset.ToString("+HH:mm", null), id) }; // ultimately we build a dropdown list, but for demo purposes you can just dump the results foreach (var item in list) Console.WriteLine(item.DisplayValue); 

Noda Time 1.1 tiene los datos de zone.tab , por lo que ahora puede hacer lo siguiente:

 ///  /// Returns a list of valid timezones as a dictionary, where the key is /// the timezone id, and the value can be used for display. ///  ///  /// The two-letter country code to get timezones for. /// Returns all timezones if null or empty. ///  public IDictionary GetTimeZones(string countryCode) { var now = SystemClock.Instance.Now; var tzdb = DateTimeZoneProviders.Tzdb; var list = from location in TzdbDateTimeZoneSource.Default.ZoneLocations where string.IsNullOrEmpty(countryCode) || location.CountryCode.Equals(countryCode, StringComparison.OrdinalIgnoreCase) let zoneId = location.ZoneId let tz = tzdb[zoneId] let offset = tz.GetZoneInterval(now).StandardOffset orderby offset, zoneId select new { Id = zoneId, DisplayValue = string.Format("({0:+HH:mm}) {1}", offset, zoneId) }; return list.ToDictionary(x => x.Id, x => x.DisplayValue); } 

Enfoque alternativo

En lugar de proporcionar un menú desplegable, puede usar un selector de zona horaria basado en mapas .

enter image description here

Obtener el desplazamiento estándar es fácil: tz.GetZoneInterval(now).StandardOffset . Eso le dará la compensación estándar “actual” (es posible que una zona cambie con el tiempo).

El filtrado puede ser apropiado para usted, no me gustaría decirlo con certeza. Ciertamente, no es ideal ya que los ID no están realmente diseñados para mostrarse. Idealmente, utilizaría los lugares de “ejemplos” de CLDR de Unicode, pero no tenemos ninguna integración de CLDR en ese frente en este momento.