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

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

Спасибо

Ответ 1

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

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

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

Ответ 2

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

offset = direction * longitude * 24 / 360

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

Ответ 3

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

Загрузка данных 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.

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

Ответ 6

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

Ответ 7

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

// [email protected]

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') ;

Ответ 8

Я написал небольшой класс 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 будет легким.

Ответ 9

К сожалению, часовые пояса недостаточно регулярны для некоторой простой функции. См. Карту в Википедия - Часовой пояс

Однако может быть вычислено очень приблизительное приближение: 1-часовая разница соответствует 15 градусам долготы (360/24).

Ответ 10

Еще одно решение - импортировать таблицу городов с часовыми поясами, а затем использовать формулу Хаверсина, чтобы найти ближайший город в этой таблице, соответствующий вашим координатам. Я разместил здесь полное описание: 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 (формула Хаверсина)

Ответ 12

Не уверен, что это полезно или нет, но я создал базу данных форм часового пояса (только для Северной Америки), которая кропотливо точна и актуальна не только для границ, но и для наблюдения за летним временем. Также формы для неофициальных исключений. Таким образом, вы можете запросить набор фигур для заданного местоположения, чтобы вернуть несколько фигур, которые применяются к этому местоположению, и выбрать правильный для времени года.

Вы можете увидеть изображение фигур в http://OnTimeZone.com/OnTimeZone_shapes.gif. Синие фигуры вокруг областей, которые не учитывают летнее время, пурпурные формируют те, которые наблюдают летнее время, и неоновые зеленые формы (маленькие и жесткие, чтобы видеть на этом уровне увеличения) предназначены для районов с неофициальным отклонением от официального часового пояса. Больше деталей о том, что доступно на сайте OnTimeZone.com.

Данные, доступные для загрузки на OnTimeZone.com, бесплатны для некоммерческого использования. Данные формы, которые недоступны для загрузки, доступны для коммерческой лицензии.

Ответ 13

Я загрузил данные, которые соответствуют 5-значным почтовым индексам для часовых поясов, и данные, которые определяют смещение UTC для каждого часового пояса в периоды DST и не-DST.

Затем я упростил данные, чтобы рассматривать только первые три цифры почтового индекса, поскольку все почтовые индексы, которые разделяют первые три цифры, очень близки друг к другу; три цифры обозначают уникальный почтовый центр распространения.

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

Вот он: https://gist.github.com/benjiwheeler/8aced8dac396c2191cf0

Ответ 14

Я использую geocoder.ca

Введите любое местоположение в Северной Америке, введите геокоды, коды областей и часовой пояс в json или jsonp.

Например: http://geocoder.ca/1600%20pennsylvania%20avenue,Washington,DC

Код города: (202)  Часовой пояс: America/New_York

Json:

{"standard":{"staddress":"Pennsylvania Ave","stnumber":"1600","prov":"DC","city":"WASHINGTON","postal":"20011","confidence":"0.8"},"longt":"-76.972948","TimeZone":"America/New_York","AreaCode":"202","latt":"38.874533"}

Ответ 15

Вы можете использовать Google Timezone api. https://maps.googleapis.com/maps/api/timezone/json?location=39.6034810,-119.6822510&timestamp=1331161200&key=YOUR_API_KEY

{
   "dstOffset" : 0,
   "rawOffset" : -28800,
   "status" : "OK",
   "timeZoneId" : "America/Los_Angeles",
   "timeZoneName" : "Pacific Standard Time"
}

Ответ 16

You can get the timezone based on the location in javascript.

function initAutocomplete() {
        // Create the autocomplete object, restricting the search to geographical
        // location types.
        autocomplete = new google.maps.places.Autocomplete(
                /** @type {!HTMLInputElement} */(document.getElementById('Location')),
                {types: ['geocode']});

        // When the user selects an address from the dropdown, populate the address
        // fields in the form.
        autocomplete.addListener('place_changed', fillInAddress);
    }

    function fillInAddress() {
        // Get the place details from the autocomplete object.
        var place = autocomplete.getPlace();

        fnGettimezone($('#Location').serialize());
        for (var component in componentForm) {
            document.getElementById(component).value = '';
            document.getElementById(component).disabled = false;
        }

        // Get each component of the address from the place details
        // and fill the corresponding field on the form.
        for (var i = 0; i < place.address_components.length; i++) {
            var addressType = place.address_components[i].types[0];
            if (componentForm[addressType]) {
                var val = place.address_components[i][componentForm[addressType]];
                document.getElementById(addressType).value = val;
            }
        }

    }


function fnGettimezone(location) {
    $.ajax({
            url: "http://maps.googleapis.com/maps/api/geocode/json?address=" + location + "&sensor=false",
            dataType: 'json',
            success: function (result) {
                 console.log(result);
                // result is already a parsed javascript object that you could manipulate directly here
                var myObject = JSON.parse(JSON.stringify(result));
                lat = myObject.results[0].geometry.location.lat;
                lng = myObject.results[0].geometry.location.lng;
                console.log(myObject);

                $.ajax({
                    url: "https://maps.googleapis.com/maps/api/timezone/json?location=" + lat + "," + lng + "&timestamp=1331161200&sensor=false",
                    dataType: 'json',
                    success: function (result) {
                        // result is already a parsed javascript object that you could manipulate directly here
                        var myObject = JSON.parse(JSON.stringify(result));
                        $('#timezone').val(myObject.timeZoneName);

                    }
                });

            }
        });
    }

Ответ 17

Этот проект создает шейп файл из данных OpenStreetMap и связывает его с несколькими библиотеками, которые его обрабатывают. Для PHP вы можете посмотреть на https://github.com/minube/geo-timezone