Определите часовой пояс по широте / долготе без использования веб-сервисов, таких как Geonames.org - PullRequest
49 голосов
/ 07 апреля 2011

есть ли возможность определить часовой пояс точки (широта / долгота) без использования веб-сервисов? Geonames.org недостаточно стабилен, чтобы я мог его использовать :( Мне нужно, чтобы это работало в PHP.

Спасибо

Ответы [ 17 ]

54 голосов
/ 07 апреля 2011

У меня была эта проблема некоторое время назад, и я сделал именно то, что предложил Адам:

  • Загрузите базу данных городов с сайта geonames.org
  • преобразовать его в компактный лат -> список часовых поясов
  • используйте реализацию R-Tree для эффективного поиска ближайшего города (или, скорее, его часового пояса) по заданной координате

IIRC потребовалось менее 1 секунды, чтобы заполнить R-Tree, и затем он мог выполнять тысячи поисков в секунду (оба на 5-летнем ПК).

13 голосов
/ 31 октября 2013

Насколько точными должны быть ваши результаты?Если приблизительной оценки достаточно, рассчитайте смещение самостоятельно:

offset = direction * longitude * 24 / 360

, где направление равно 1 для востока, -1 для запада и долгота в (-180,180)

10 голосов
/ 08 мая 2012

Я столкнулся с этой проблемой, работая над другим проектом, и очень глубоко изучил ее. Я обнаружил, что во всех существующих решениях отсутствуют основные пути.

Загрузка данных GeoNames и использование некоторого пространственного индекса для поиска ближайшей точки, безусловно, вариант, и он будет часто давать правильный результат, но он может легко потерпеть неудачу, если точка запроса находится на неправильной стороне границы часового пояса от ближайшей точки в базе данных.

Более точный метод состоит в том, чтобы использовать цифровую карту часовых поясов и написать код, чтобы найти полигон в той карте, которая содержит заданную точку запроса. К счастью, есть отличная карта часовых поясов мира, доступная по номеру http://efele.net/maps/tz/world/ (больше не поддерживается ). Чтобы написать эффективный механизм запросов, вам необходимо:

  • Разобрать формат шейп-файла ESRI во полезное внутреннее представление.
  • Напишите код точки в многоугольнике, чтобы проверить, находится ли заданная точка запроса в заданном многоугольнике.
  • Напишите эффективный пространственный индекс поверх данных многоугольника, чтобы вам не нужно было проверять каждый многоугольник, чтобы найти содержащий его.
  • Обработка запросов, которые не содержатся ни в каком многоугольнике (например, в океане). В таких случаях вы должны «привязаться» к ближайшему полигону на определенное расстояние и вернуться к «естественному» часовому поясу (который определяется только долготой) в открытом океане. Для этого вам понадобится код для вычисления расстояния между точкой запроса и отрезком линии многоугольника (это нетривиально, поскольку широта и долгота неевклидовой системы координат), и ваш пространственный индекс должен быть возможность возвращать соседние полигоны, а не только потенциально содержащие полигоны.

Каждый из них достоин своей страницы вопросов / ответов о переполнении стека.

Сделав вывод, что ни одно из существующих решений не отвечало моим потребностям, я написал собственное решение и сделал его доступным здесь:

http://askgeo.com

AskGeo использует цифровую карту и имеет высокооптимизированный пространственный индекс, который позволяет выполнять более 10000 запросов в секунду на моем компьютере в одном потоке. И это потокобезопасно, поэтому, конечно, возможна даже более высокая пропускная способность Это серьезный кусок кода, и его разработка заняла много времени, поэтому мы предлагаем его по коммерческой лицензии.

Он написан на Java, поэтому использование его на PHP потребует:

http://php -java-bridge.sourceforge.net / DOC / how_it_works.php

Мы также открыты для портирования за вознаграждение. Подробнее о ценах и подробной документации см. http://askgeo.com.

Надеюсь, это полезно. Это, безусловно, было полезно для проекта, над которым я работал.

8 голосов
/ 27 января 2013

Я знаю, что это старо, но я потратил некоторое время на поиски этого ответа.Нашел что-то очень полезное.Google выполняет поиск часовых поясов по long / lat. Больше нет свободного уровня : - /

https://developers.google.com/maps/documentation/timezone/

5 голосов
/ 07 апреля 2011

Если вы знаете многоугольник часового пояса, вы сможете узнать, находится ли внутри него определенный широту / долготу.

База данных мировых часовых поясов enter image description here

Данные о многоугольнике широты / долготы enter image description here

5 голосов
/ 21 января 2012

Для областей на суше существуют карты шейп-файлов , которые были созданы для часовых поясов базы данных tz (Olson).Они обновляются не так регулярно, как сама база данных tz, но это отличная отправная точка и, по-видимому, очень точная для большинства целей.

3 голосов
/ 21 марта 2013

Как насчет этого?

// 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') ;
2 голосов
/ 30 октября 2013

Я написал небольшой Java-класс для этого. Это может быть легко переведено на PHP. База данных встроена в сам код. Это с точностью до 22 км.

https://sites.google.com/a/edval.biz/www/mapping-lat-lng-s-to-timezones

Весь код в основном такой:

         if (lng < -139.5) {
          if (lat < 68.5) {
           if (lng < -140.5) {
            return 371;
           } else {
            return 325;
           }

... поэтому я предполагаю, что перевод на PHP будет простым.

1 голос
/ 13 февраля 2013

Вы можете использовать границы часового пояса, предоставленные здесь:

http://www.opensource.apple.com/source/TimeZoneData/

1 голос
/ 13 декабря 2012

Другое решение - импортировать таблицу городов с часовыми поясами, а затем использовать формулу Хаверсайна, чтобы найти ближайший город в этой таблице, соответствующий вашим координатам.Я разместил полное описание здесь: http://sylnsr.blogspot.com/2012/12/find-nearest-location-by-latitude-and.html

Для примера загрузки данных в MySQL я разместил здесь пример (с источниками для загрузки небольшого дампа данных): http://sylnsr.blogspot.com/2012/12/load-timezone-data-by-city-and-country.html

Обратите внимание, что точность поиска будет зависеть от того, насколько полны ваши поисковые данные.

Кредиты и справочники: MySQL Great Circle Distance (формула Haversine)

...