关于时区:我应如何填写Noda Time的IANA / Olson时区列表?

How should I populate a list of IANA / Olson time zones from Noda Time?

我在应用程序中使用NodaTime,我需要用户从下拉列表中选择他们的时区。 我有以下软要求:

1)该列表仅包含对于真实场所现在和将来合理有效的选择。 应过滤掉历史,模糊和通用时区。

2)列表应首先按UTC偏移量排序,然后按时区名称排序。 这有希望将它们置于对用户有意义的顺序中。

我写了下面的代码,它确实有效,但并不完全是我所追求的。 可能需要调整滤波器,我宁愿让偏移代表基本(非dst)偏移,而不是当前偏移。

建议?建议?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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具有zone.tab数据,因此您现在可以执行以下操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/// <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);
}

替代方法

您可以使用基于地图的时区选择器,而不是提供下拉菜单。

enter image description here


获得标准偏移很容易 - tz.GetZoneInterval(now).StandardOffset。 这将为您提供"当前"标准偏移(区域可能随时间变化)。

过滤可能适合您 - 我不想肯定地说。 由于ID并非真正用于显示,因此它当然不是理想的。 理想情况下,您将使用Unicode CLDR"示例"位置,但目前我们在此方面没有任何CLDR集成。