timezone - ¿Cómo debo rellenar una lista de zonas horarias IANA/Olson desde Noda Time?
nodatime (2)
Noda Time 1.1 tiene los datos de zone.tab , por lo que ahora puede hacer lo siguiente:
/// <summary>
/// Returns a list of valid timezones as a dictionary, where the key is
/// the timezone id, and the value can be used for display.
/// </summary>
/// <param name="countryCode">
/// The two-letter country code to get timezones for.
/// Returns all timezones if null or empty.
/// </param>
public IDictionary<string, string> 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 .
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 ser eliminadas.
2) La lista debe ordenarse primero por desplazamiento UTC, y luego por nombre de zona horaria. Esperemos que esto los ponga en un orden que sea significativo para el usuario.
He escrito el siguiente código, que sí funciona, pero no tiene exactamente lo que busco. El filtro probablemente deba ajustarse, y prefiero que el desplazamiento represente el desplazamiento base (no 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);
Obtener el desplazamiento estándar es fácil: tz.GetZoneInterval(now).StandardOffset
. 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 seguridad. Ciertamente no es ideal, ya que las ID no están realmente diseñadas para su visualización. Lo ideal sería utilizar los lugares de "ejemplo" de Unicode CLDR, pero no tenemos ninguna integración de CLDR en ese frente en este momento.