Javascript 在不使用 Geonames.org 等网络服务的情况下,根据纬度/经度确定时区
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5584602/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Determine timezone from latitude/longitude without using web services like Geonames.org
提问by Jacek Francuz
is there any possibility to determine the timezone of point (lat/lon) without using webservices? Geonames.org is not stable enough for me to use :( I need this to work in PHP.
是否有可能在不使用网络服务的情况下确定点(纬度/经度)的时区?Geonames.org 不够稳定,我无法使用 :( 我需要它在 PHP 中工作。
Thanks
谢谢
回答by Michael Borgwardt
I had this problem a while back and did exactly what adam suggested:
不久前我遇到了这个问题,并且完全按照亚当的建议进行了操作:
- Download the database of citiesfrom geonames.org
- convert it to a compact lat/lon -> timezone list
- use an R-Treeimplementation to efficiently lookup the nearest city (or rather, its timezone) to a given coordinate
IIRC it took less than 1 second to populate the R-Tree, and it could then perform thousands of lookups per second (both on a 5 year old PC).
IIRC 填充 R 树的时间不到 1 秒,然后它可以每秒执行数千次查找(均在 5 年前的 PC 上进行)。
回答by Christian Stade-Schuldt
How exact do your results have to be? If a rough estimate is enough, calculate the offset yourself:
你的结果必须有多精确?如果粗略估计就足够了,请自行计算偏移量:
offset = direction * longitude * 24 / 360
where direction is 1 for east, -1 for west, and longitude is in (-180,180)
其中方向为 1 为东,-1 为西,经度为 (-180,180)
回答by James D
I ran into this problem while working on another project and looked into it very deeply. I found all of the existing solutions to be lacking in major ways.
我在做另一个项目时遇到了这个问题,并对其进行了深入研究。我发现所有现有的解决方案在主要方面都缺乏。
Downloading the GeoNames data and using some spatial index to look up the nearest point is definitely an option, and it will yield the correct result a lot of the time, but it can easily fail if a query point is on the wrong side of a time zone border from the nearest point in the database.
下载 GeoNames 数据并使用一些空间索引来查找最近的点绝对是一种选择,它会在很多时候产生正确的结果,但如果查询点在时间的错误一侧,它很容易失败从数据库中最近的点开始的区域边界。
A more accurate method is to use a digital map of the time zones and to write code to find the polygon in that map that contains a given query point. Thankfully, there is an excellent map of the time zones of the world available at http://efele.net/maps/tz/world/(not maintained anymore). To write an efficient query engine, you need to:
更准确的方法是使用时区的数字地图并编写代码来查找该地图中包含给定查询点的多边形。值得庆幸的是,没有可用的世界时区的一个极好的地图在http://efele.net/maps/tz/world/(不保持了)。要编写高效的查询引擎,您需要:
- Parse the ESRI shapefile format into a useful internal representation.
- Write point-in-polygon code to test whether a given query point is in a given polygon.
- Write an efficient spatial index on top of the polygon data so that you don't need to check every polygon to find the containing one.
- Handle queries that are not contained by any polygon (e.g., in the ocean). In such cases, you should "snap to" the nearest polygon up to a certain distance, and revert to the "natural" time zone (the one determined by longitude alone) in the open ocean. To do this, you will need code to compute the distance between a query point and a line segment of a polygon (this is non-trivial since latitude and longitude are a non-Euclidean coordinate system), and your spatial index will need to be able to return nearby polygons, not just potentially containing polygons.
- 将 ESRI shapefile 格式解析为有用的内部表示。
- 编写点入多边形代码来测试给定的查询点是否在给定的多边形中。
- 在多边形数据之上编写一个有效的空间索引,这样您就不需要检查每个多边形来找到包含它的多边形。
- 处理不包含在任何多边形中的查询(例如,在海洋中)。在这种情况下,您应该“对齐”到一定距离内最近的多边形,并恢复到公海中的“自然”时区(仅由经度确定的时区)。为此,您将需要代码来计算查询点与多边形线段之间的距离(这很重要,因为纬度和经度是非欧几里得坐标系),并且您的空间索引需要为能够返回附近的多边形,而不仅仅是可能包含多边形。
Each of those are worthy of their own Stack Overflow question/answer page.
每一个都值得拥有自己的 Stack Overflow 问题/答案页面。
After concluding that none of the existing solutions out there met my needs, I wrote my own solution and made it available here:
在得出结论认为现有的解决方案都不能满足我的需求后,我编写了自己的解决方案并在此处提供:
AskGeo uses a digital map and has a highly optimized spatial index that allows for running more than 10,000 queries per second on my computer in a single thread. And it is thread safe, so even higher throughput is certainly possible. This is a serious piece of code, and it took us a long time to develop, so we are offering it under a commercial license.
AskGeo 使用数字地图并具有高度优化的空间索引,允许在我的计算机上以单个线程每秒运行超过 10,000 次查询。而且它是线程安全的,因此更高的吞吐量当然是可能的。这是一段严肃的代码,我们花了很长时间来开发,所以我们在商业许可下提供它。
It is written in Java, so using it in PHP would involve using:
它是用 Java 编写的,因此在 PHP 中使用它需要使用:
http://php-java-bridge.sourceforge.net/doc/how_it_works.php
http://php-java-bridge.sourceforge.net/doc/how_it_works.php
We are also open to porting it for a bounty. For details on the pricing, and for detailed documentation, see http://askgeo.com.
我们也愿意移植它以获得赏金。有关定价的详细信息和详细文档,请参阅http://askgeo.com。
I hope this is useful. It certainly was useful for the project I was working on.
我希望这是有用的。这对我正在从事的项目当然很有用。
回答by Jeff Vdovjak
I know this is old, but I spent some time looking for this answer. Found something very useful. Google does time zone lookups by long/lat. No free tier anymore:-/
我知道这很旧,但我花了一些时间寻找这个答案。发现了一个非常有用的东西。Google 按 long/lat 进行时区查找。不再有免费层:-/
回答by Tim Parenti
For areas on land, there are some shapefile mapsthat have been made for the timezones of the tz (Olson) database. They're not updated quite as regularly as the tz database itself, but it's a great starting point and seems to be very accurate for most purposes.
对于陆地区域,已经为 tz (Olson) 数据库的时区制作了一些shapefile 地图。它们不像 tz 数据库本身那样定期更新,但它是一个很好的起点,对于大多数用途似乎非常准确。
回答by daniellmb
You should be able to, if you know the polygon of the timezone to see if a given lat/lon is inside it.
如果您知道时区的多边形以查看给定的纬度/经度是否在其中,您应该能够。
回答by j-bin
How about this ?
这个怎么样 ?
// ben@jp
function get_nearest_timezone($cur_lat, $cur_long, $country_code = '') {
$timezone_ids = ($country_code) ? DateTimeZone::listIdentifiers(DateTimeZone::PER_COUNTRY, $country_code)
: DateTimeZone::listIdentifiers();
if($timezone_ids && is_array($timezone_ids) && isset($timezone_ids[0])) {
$time_zone = '';
$tz_distance = 0;
//only one identifier?
if (count($timezone_ids) == 1) {
$time_zone = $timezone_ids[0];
} else {
foreach($timezone_ids as $timezone_id) {
$timezone = new DateTimeZone($timezone_id);
$location = $timezone->getLocation();
$tz_lat = $location['latitude'];
$tz_long = $location['longitude'];
$theta = $cur_long - $tz_long;
$distance = (sin(deg2rad($cur_lat)) * sin(deg2rad($tz_lat)))
+ (cos(deg2rad($cur_lat)) * cos(deg2rad($tz_lat)) * cos(deg2rad($theta)));
$distance = acos($distance);
$distance = abs(rad2deg($distance));
// echo '<br />'.$timezone_id.' '.$distance;
if (!$time_zone || $tz_distance > $distance) {
$time_zone = $timezone_id;
$tz_distance = $distance;
}
}
}
return $time_zone;
}
return 'none?';
}
//timezone for one NY co-ordinate
echo get_nearest_timezone(40.772222,-74.164581) ;
// more faster and accurate if you can pass the country code
echo get_nearest_timezone(40.772222, -74.164581, 'US') ;
回答by Tim Cooper
I've written a small Java class to do this. It could be easily translated to PHP. The database is embedded in the code itself. It's accurate to 22km.
我已经编写了一个小的 Java 类来做到这一点。它可以很容易地转换为 PHP。数据库嵌入在代码本身中。精确到22公里。
https://sites.google.com/a/edval.biz/www/mapping-lat-lng-s-to-timezones
https://sites.google.com/a/edval.biz/www/mapping-lat-lng-s-to-timezones
The whole code is basically stuff like this:
整个代码基本上是这样的:
if (lng < -139.5) {
if (lat < 68.5) {
if (lng < -140.5) {
return 371;
} else {
return 325;
}
...so I presume a translation to PHP would be easy.
...所以我认为翻译成 PHP 会很容易。
回答by Steve
Not sure if this is useful or not, but I built a database of timezone shapes (for North America only), which is painstakingly accurate and current not just for borders, but also for daylight saving time observance. Also shapes for unofficial exceptions. So you could query the set of shapes for a given location could return multiple shapes that apply to that location, and choose the correct one for the time of year.
不确定这是否有用,但我建立了一个时区形状数据库(仅适用于北美),该数据库非常准确,不仅适用于边界,而且适用于夏令时遵守。也是非官方例外的形状。因此,您可以查询给定位置的一组形状,可以返回适用于该位置的多个形状,并为一年中的时间选择正确的形状。
You can see an image of the shapes at http://OnTimeZone.com/OnTimeZone_shapes.gif. Blue shapes are around areas that do not observe daylight saving time, magenta shapes those that do observe daylight saving time, and neon green shapes (small and tough to see at that zoom level) are for areas with unofficial deviation from the official time zone. Lots more detail on that available at the OnTimeZone.com site.
您可以在http://OnTimeZone.com/OnTimeZone_shapes.gif 上看到形状的图像。蓝色形状围绕不遵守夏令时的区域,洋红色形状那些遵守夏令时的区域,霓虹绿色形状(在该缩放级别上小而难以看到)用于与官方时区有非官方偏差的区域。OnTimeZone.com 网站上提供了更多详细信息。
The data available for download at OnTimeZone.com is free for non-commercial use. The shape data, which is not available for download, is available for commercial license.
可在 OnTimeZone.com 上下载的数据可免费用于非商业用途。无法下载的形状数据可用于商业许可。
回答by MillKa
Unfortunately, time zones are not regular enough for some simple function. See the map in Wikipedia - Time Zone
不幸的是,时区对于一些简单的功能来说不够规则。查看维基百科中的地图- 时区
However, some very rough approximation can be calculated: 1 hour difference corresponds to 15 degrees longitude (360 / 24).
但是,可以计算出一些非常粗略的近似值:1 小时的差异对应于 15 度经度 (360 / 24)。