获取一个国家的默认时区(通过 CultureInfo)

Posted

技术标签:

【中文标题】获取一个国家的默认时区(通过 CultureInfo)【英文标题】:Get the default timezone for a country (via CultureInfo) 【发布时间】:2013-11-10 19:19:07 【问题描述】:

是否有提供每个国家/地区默认时区的程序或表格?

是的,美国、加拿大和俄罗斯有多个时区。 (我认为每个其他国家/地区都只有一个。)但是最好从最有可能的国家开始,而不是仅仅提供从 GMT 开始的列表。

最好在 C# 中,但我会接受它并转换为 C#。

【问题讨论】:

中国。印度。伊朗。巴西.... 什么是“默认时区”???国家首都所在的区域? 澳大利亚至少有三个时区,一些州(但不是全部)有夏令时,美国的印第安纳州至少使用两个时区。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是题外话,因为它们往往会吸引固执己见的答案和垃圾邮件。相反,请描述问题以及迄今为止为解决该问题所做的工作。 @Andrew,有趣的事实:中国确实只有一个时区。疯了,如果你想想那个国家的规模。但是蒙古有两个,应该平衡它;) 【参考方案1】:

正如问题的 cmets 中所确定的,您无法为每个国家/地区获得一个时区。拥有多个时区的国家/地区的例子太多了。

可以做的是将标准IANA/Olson time zones 列表过滤到特定国家/地区可用的列表。

在 C# 中执行此操作的一种方法是使用 Noda Time:

IEnumerable<string> zoneIds = TzdbDateTimeZoneSource.Default.ZoneLocations
    .Where(x => x.CountryCode == countryCode)
    .Select(x => x.ZoneId);

传递两位数的 ISO-3166 国家/地区代码,例如 "AU" 代表澳大利亚。结果是:

"Australia/Lord_Howe",
"Australia/Hobart",
"Australia/Currie",
"Australia/Melbourne",
"Australia/Sydney",
"Australia/Broken_Hill",
"Australia/Brisbane",
"Australia/Lindeman",
"Australia/Adelaide",
"Australia/Darwin",
"Australia/Perth",
"Australia/Eucla"

如果出于某种原因您希望 Windows 时区标识符可以与 TimeZoneInfo 对象一起使用,Noda Time 也可以映射这些标识符:

var source = TzdbDateTimeZoneSource.Default;
IEnumerable<string> windowsZoneIds = source.ZoneLocations
    .Where(x => x.CountryCode == countryCode)
    .Select(tz => source.WindowsMapping.MapZones
        .FirstOrDefault(x => x.TzdbIds.Contains(
                             source.CanonicalIdMap.First(y => y.Value == tz.ZoneId).Key)))
    .Where(x => x != null)
    .Select(x => x.WindowsId)
    .Distinct()

再次,使用"AU" 调用澳大利亚返回:

"Tasmania Standard Time",
"AUS Eastern Standard Time",
"Cen. Australia Standard Time",
"E. Australia Standard Time",
"AUS Central Standard Time",
"W. Australia Standard Time"

如果您想知道这些数据的可靠性,国家到 tzid 的映射是 IANA 时区数据库本身的一部分,位于 zone.tab 文件中。 IANA 到 Windows 的映射数据来自Unicode CLDR supplemental data。没有比这更接近“官方”的了。

【讨论】:

您可以尝试对FO 国家代码进行相同的操作吗? (Faroi Islands) 我可以在文件 (zone.tab) 中找到代码,但在 C# 中我没有得到此代码的结果.. 试试我刚刚做的编辑。我没有考虑到 Windows 映射中的 ID 并不总是 TZDB 规范的。 对于windows时区,它不适用于所有情况,例如HR。 这会产生多余的时区。例如,美国只有 3-4 个时区,但这会返回 29 个时区,其中许多是同一时区!【参考方案2】:

可能不是您想要的,但试试这个:http://msdn.microsoft.com/en-us/library/system.timezoneinfo.aspx

获取特定时区:

TimeZoneInfo tZone = TimeZoneInfo.FindSystemTimeZoneById("E. Australia Standard Time");

查看可用区域:

ReadOnlyCollection<TimeZoneInfo> zones = TimeZoneInfo.GetSystemTimeZones();

foreach (TimeZoneInfo zone in zones)

     Console.WriteLine(zone.Id);

【讨论】:

【参考方案3】:

为了获得 CountryCode -> TimeZoneInfo 映射,我使用了 Matt 的答案(第二个代码 sn-p),但它在很多情况下都不起作用。找到更简单、更可靠的解决方案(使用相同的 Noda 时间): TzdbDateTimeZoneSource.Default.WindowsMapping.MapZones 基本上拥有所有数据。

代码示例:

Dictionary<string, TimeZoneInfo> GetIsoToTimeZoneMapping()

    var source = TzdbDateTimeZoneSource.Default;

    return source.WindowsMapping.MapZones
        .GroupBy(z => z.Territory)
        .ToDictionary(grp => grp.Key, grp => GetTimeZone(source, grp));


 TimeZoneInfo GetTimeZone(TzdbDateTimeZoneSource source, IEnumerable<MapZone> territoryLocations)

    var result = territoryLocations
        .Select(l => l.WindowsId)
        .Select(TimeZoneInfo.FindSystemTimeZoneById)
        //pick timezone with the minimum offset
        .Aggregate((tz1, tz2) => tz1.BaseUtcOffset < tz2.BaseUtcOffset ? tz1 : tz2);

    return result;

【讨论】:

【参考方案4】:

最新的 Windows 版本包含文件 %WINDIR%\Globalization\Time Zone\timezoneMapping.xml,它将 Olson 映射到 Windows 时区,您可以将其作为常规 XML 查询。我不知道,但也许 C# 已经有一个可以使用它的类。

【讨论】:

实现这个的好方法可以在这里找到codeofmatt.com/2014/04/07/working-with-time-zone-names-in-net【参考方案5】:

当用户首次登录时,我使用了 Microsoft 用于 Windows 的每个国家/地区的默认时区。他们在https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/default-time-zones 列出了这些时区。

我还创建了一个脚本,该脚本将该表解析为位于 https://github.com/rahulgi/default-timezones 的 JSON 文件。

【讨论】:

【参考方案6】:

有些国家有多个时区,例如俄罗斯。

在我的解决方案中,如果您有可用的经度信息,我会使用NodaTime,我会选择该国家/地区的最佳时区。

var countryName = "Russia";
var longitude = 40.332206;

var zones = TzdbDateTimeZoneSource.Default.ZoneLocations.Where(x => x.CountryName == countryName).AsQueryable();
if (!double.IsNaN(longitude))

    zones = zones.OrderBy(o => this.Distance(o.Latitude, longitude, o.Latitude, o.Longitude, DistanceUnit.Kilometer));

var bestZone = zones.FirstOrDefault();
var dateTimeZone = TzdbDateTimeZoneSource.Default.ForId(bestZone.ZoneId);

var newTime = DateTime.UtcNow.AddSeconds(dateTimeZone.MaxOffset.Seconds);

计算地理坐标的距离

public enum DistanceUnit  StatuteMile, Kilometer, NauticalMile ;

private double Distance(double lat1, double lon1, double lat2, double lon2, DistanceUnit unit)

    double rlat1 = Math.PI * lat1 / 180;
    double rlat2 = Math.PI * lat2 / 180;
    double theta = lon1 - lon2;
    double rtheta = Math.PI * theta / 180;
    double dist =
        Math.Sin(rlat1) * Math.Sin(rlat2) + Math.Cos(rlat1) *
        Math.Cos(rlat2) * Math.Cos(rtheta);
    dist = Math.Acos(dist);
    dist = dist * 180 / Math.PI;
    dist = dist * 60 * 1.1515;

    switch (unit)
    
        case DistanceUnit.Kilometer:
            return dist * 1.609344;
        case DistanceUnit.NauticalMile:
            return dist * 0.8684;
        default:
        case DistanceUnit.StatuteMile: //Miles
            return dist;
    

【讨论】:

以上是关于获取一个国家的默认时区(通过 CultureInfo)的主要内容,如果未能解决你的问题,请参考以下文章

使用 pytz 获取时区的国家代码?

如何在 Flutter 中使用 OpenWeather API 的时区属性获取任何城市/国家的当前时间?

javascript 按国家/地区代码设置默认时区

获取iOS时区中的城市和国家/地区列表

如何在android中获取移动时区的缩写/国家代码?

从ios中的facebook登录获取国家名称和时区