有没有一个程序或表格可以为每个国家提供默认的时区?
是的,美国、加拿大和俄罗斯拥有多个时区。(我认为其他每个国家只有一个时区。) 但是如果我们已知某个国家,最好从该国家开始,而不仅仅提供以GMT为起点的列表。
最好用C#,但我会接受任何语言并转换成C#。
有没有一个程序或表格可以为每个国家提供默认的时区?
是的,美国、加拿大和俄罗斯拥有多个时区。(我认为其他每个国家只有一个时区。) 但是如果我们已知某个国家,最好从该国家开始,而不仅仅提供以GMT为起点的列表。
最好用C#,但我会接受任何语言并转换成C#。
正如问题评论中指出的那样,你无法为每个国家获取单一的时区。因为有太多国家拥有多个时区。
你可以过滤标准IANA/Olson时区列表,只保留特定国家中可用的时区。
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映射是IANA时区数据库本身的一部分,位于zone.tab文件中。IANA到Windows映射数据来自Unicode CLDR补充数据。没有比这更“官方”的了。
FO
国家代码呢?(即 法罗群岛
)我在文件 (zone.tab
) 中找到了该代码,但是在 C#
中却没有得到任何结果。 - Alex代码示例:
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;
}
也许不完全符合您的要求,但可以尝试使用以下链接: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);
}
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;
}
}
最新的Windows版本包含文件%WINDIR%\Globalization\Time Zone\timezoneMapping.xml
,它将Olson映射到Windows时区,您可以像查询常规XML
一样查询它。我不知道但也许C#
已经有一个可以使用它的类。
我使用了微软在Windows中用户首次登录时使用的每个国家/地区的默认时区。它们列在https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/default-time-zones。
我还创建了一个脚本,将该表解析为JSON文件,位于https://github.com/rahulgi/default-timezones。