Come dovrei popolare un elenco di fusi orari IANA / Olson da Noda Time?

Sto usando NodaTime in un’applicazione e ho bisogno che l’utente selezioni il loro fuso orario da un elenco a discesa. Ho i seguenti requisiti soft:

1) L’elenco contiene solo scelte ragionevolmente valide per il presente e il futuro prossimo per luoghi reali. È necessario filtrare i fusi orari storici, oscuri e generici.

2) L’elenco deve essere ordinato prima per offset UTC e quindi per nome fuso orario. Questo li spera li mette in un ordine che è significativo per l’utente.

Ho scritto il seguente codice, che funziona davvero, ma non ha esattamente quello che sto cercando. Probabilmente il filtro deve essere regolato, e preferisco che l’offset rappresenti l’offset di base (non-dst), piuttosto che l’offset corrente.

Suggerimenti? Raccomandazioni?

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 ha i dati zone.tab , quindi ora puoi fare quanto segue:

 ///  /// 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); } 

Approccio alternativo

Invece di fornire un menu a discesa, puoi utilizzare un selettore del fuso orario basato sulla mappa .

inserisci la descrizione dell'immagine qui

Ottenere l’offset standard è facile – tz.GetZoneInterval(now).StandardOffset . Questo ti darà lo scostamento standard “attuale” (è ansible che una zona cambi nel tempo).

Il filtro potrebbe essere appropriato per te – non vorrei dirlo con certezza. Non è certamente l’ ideale in quanto gli ID non sono realmente progettati per la visualizzazione. Idealmente useresti i posti di “esempio” Unicode CLDR, ma al momento non abbiamo alcuna integrazione CLDR su questo fronte.