获取国家/地区的默认时区(通过CultureInfo)

时间:2013-10-30 23:00:17

标签: c# timezone country

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

是的,美国,加拿大和美国俄罗斯有多个时区。 (我认为每个其他国家只有一个。)但如果一个国家知道而不是仅仅提供从格林威治标准时间开始的名单,最好开始最有可能。

最好是在C#中,但我会把它带入任何东西并转换为C#。

6 个答案:

答案 0 :(得分:19)

如问题评论中所述,您无法为每个国家/地区获得单个时区。有多个时区的国家太多了。

可以做的是将标准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"

如果由于某种原因你想要使用TimeZoneInfo对象的Windows时区标识符,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映射的国家/地区是zone.tab文件中IANA时区数据库本身的一部分。 IANA到Windows映射数据来自Unicode CLDR supplemental data。它与“官方”没有任何关系。

答案 1 :(得分:3)

可能不是您想要的,但请尝试: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);
}

答案 2 :(得分:1)

为了获得CountryCode - &gt; TimeZoneInfo映射我使用了来自Matt(第二个代码片段)的答案,但它在许多情况下都不起作用。发现更简单,更可靠的解决方案(使用相同的Noda Time):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;
}

答案 3 :(得分:0)

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

答案 4 :(得分:0)

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

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

答案 5 :(得分:0)

一些国家将更多时区作为一个时区,例如俄罗斯。

在我的解决方案中,如果您有可用的经度信息,我会使用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;
    }
}