按国家和地区获取时区

时间:2011-11-02 08:56:22

标签: c# timezone

我正在开发一个在C#/ .NET平台上发送应用程序的简报。我最近添加了模块,使用maxmind.com数据库通过IP地址检索收件人的国家和地区。

例如,我可以获得一些示例IP地址的以下信息:

Country Code: DE
Country Name: Germany   
Region Name:  Hessen 
City:         Frankfurt Am Main
Latitude:     50.1167
Longitude:    8.6833 

我现在需要的是使用此信息获取用户的时区。

我知道有一些GeoIp数据库也提供了时区,但我需要使用这个具体的GeoIp数据库。此外,这里不能使用javascript确定时间偏移的方法。

可能我可以使用国家和地区名称以某种方式获得时区吗?

4 个答案:

答案 0 :(得分:10)

最后,经过长时间的研究,我找到了解决方案。它可能不太准确,但它不需要远程服务的依赖性。

我发现maxmind的数据库提供了来自Olsen数据库(也就是tz数据库)的区域和时区之间的映射文件:http://www.maxmind.com/timezone.txt

第二步是在.NET时区中转换Olsen时区。在这里找到了最合适的解决方案:http://www.timdavis.com.au/data/olson-time-zone-database-to-standard-windows-time-zone-v01/ 所以我对它进行了一些编辑并将其转换为CSV文件以从.NET中读取它。

希望它会对某人有所帮助。

答案 1 :(得分:2)

答案 2 :(得分:1)

自问这个问题以来已经有一段时间了,但可能有助于其他人......

当您使用maxmind API中的DatabaseReader对象时,已经有一个属性location.timeZone,您可以从GeoIP类返回的对象中检索它,从maxmind查看API docs

答案 3 :(得分:0)

某些国家(例如俄罗斯)拥有更多的时区。

在我的解决方案中,我使用NodaTime,您可以使用maxmind中的经度信息来找到最佳匹配项。

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

var zones = TzdbDateTimeZoneSource.Default.ZoneLocations.Where(x => x.CountryName == countryName).AsQueryable();
if (!double.IsNaN(longitude))
{
    //If a longitude available use the information to order the zones by distance
    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:
            return dist;
    }
}
相关问题