есть ли возможность определить часовой пояс точки (lat / lon) без использования веб-сервисов? Geonames.org недостаточно стабилен для меня 🙁 Мне нужно это для работы на PHP.
благодаря
У меня была эта проблема некоторое время назад, и я сделал то, что предложил адам:
IIRC потребовалось меньше 1 секунды, чтобы заполнить R-Tree, и затем он мог выполнять тысячи поисков в секунду (как на 5-летнем ПК).
Я столкнулся с этой проблемой, работая над другим проектом и глубоко задумался. Я обнаружил, что всех существующих решений не хватает по-крупному.
Загрузка данных GeoNames и использование какого-либо пространственного индекса для поиска ближайшей точки, безусловно, является опцией, и она даст правильный результат много времени, но может легко провалиться, если точка запроса находится на неправильной стороне времени зоны от ближайшей точки базы данных.
Более точный метод – использовать цифровую карту часовых поясов и написать код, чтобы найти многоугольник на этой карте, содержащий заданную точку запроса. К счастью, есть прекрасная карта часовых поясов мира, доступная по адресу http://efele.net/maps/tz/world/ . Чтобы написать эффективный механизм запросов, вам необходимо:
Каждый из них достоин собственной страницы вопросов / ответов о переполнении стека.
Выяснив, что ни одно из существующих решений не удовлетворило мои потребности, я написал свое собственное решение и сделал его доступным здесь:
AskGeo использует цифровую карту и имеет оптимизированный пространственный индекс, который позволяет запускать более 10000 запросов в секунду на моем компьютере в одном потоке. И это потокобезопасно, поэтому даже более высокая пропускная способность, безусловно, возможна. Это серьезная часть кода, и нам потребовалось много времени для разработки, поэтому мы предлагаем ее по коммерческой лицензии.
Он написан на Java, поэтому использование его в PHP предполагает использование:
http://php-java-bridge.sourceforge.net/doc/how_it_works.php
Мы также открыты для портирования его за щедрость. Подробнее о ценах и подробной документации см. На странице http://askgeo.com .
Надеюсь, это полезно. Конечно, это было полезно для проекта, над которым я работал.
Насколько точны ваши результаты? Если приблизительной оценки достаточно, рассчитывайте смещение самостоятельно:
offset = direction * longitude * 24 / 360
где направление 1 для востока, -1 для запада, а долгота – (-180 180)
Я знаю, что это старо, но я потратил некоторое время на поиск этого ответа. Нашел что-то очень полезное. Google выполняет поиск по часовому поясу по длине / лат. 2500 в день (или 100 000 для бизнес-пользователей).
Вы должны уметь, если знаете полигон часового пояса, чтобы увидеть, находится ли данный лат / лон внутри него.
База данных мирового времени
Локальные / долготные данные многоугольника
Для областей на суше имеются карты шейп-файлов , которые были сделаны для временных интервалов базы данных tz (Olson). Они не обновляются так же регулярно, как и сама база данных tz, но это отличная отправная точка и, по-видимому, очень точная для большинства целей.
Как насчет этого ?
// 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') ;
Для этого я написал небольшой класс 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 час соответствует 15 градусам долготы (360/24).
Другое решение – импортировать таблицу городов с часовыми поясами, а затем использовать формулу Хаверсина, чтобы найти ближайший город в этой таблице, соответствующий вашим координатам. Я опубликовал полное описание здесь: 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 и-country.html
Обратите внимание, что точность поиска будет основана на том, насколько полны ваши данные поиска.
Кредиты и ссылки: MySQL Great Circle Distance (формула Хаверсина)
Вы можете использовать границы часовых поясов, приведенные здесь:
Не уверен, что это полезно или нет, но я создал базу данных о часовых поясах (только для Северной Америки), которая кропотливо точная и актуальная не только для границ, но и для наблюдения за летним временем. Также формы для неофициальных исключений. Таким образом, вы можете запросить набор фигур для данного местоположения, чтобы вернуть несколько фигур, которые применяются к этому местоположению, и выбрать правильный для времени года.
Вы можете увидеть изображение фигур по адресу http://OnTimeZone.com/OnTimeZone_shapes.gif . Синие фигуры вокруг областей, которые не учитывают летнее время, пурпурные формируют те, которые наблюдают летнее время, и неоновые зеленые формы (маленькие и жесткие, чтобы видеть на этом уровне увеличения) предназначены для районов с неофициальным отклонением от официального часового пояса. Больше деталей о том, что доступно на сайте OnTimeZone.com.
Данные, доступные для загрузки на OnTimeZone.com, бесплатны для некоммерческого использования. Данные формы, которые недоступны для загрузки, доступны для коммерческой лицензии.
Я загружал данные, которые соответствуют 5-значным почтовым индексам для часовых поясов, и данные, которые определяют смещение UTC для каждого часового пояса в периоды DST и не-DST.
Затем я упростил данные, чтобы рассматривать только первые три цифры почтового индекса, поскольку все почтовые индексы, которые разделяют первые три цифры, очень близки друг к другу; три цифры обозначают уникальный почтовый центр распространения.
Полученный Json-файл требует, чтобы вы определили, действительно ли вы подвергаетесь DST, и, вероятно, здесь есть некоторая неточность. Но это довольно хорошее локальное решение, которое очень компактно и легко запрашивать.
Вот он: https://gist.github.com/benjiwheeler/8aced8dac396c2191cf0
Я использую 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"}
Вы можете использовать Google Timezone api. https://maps.googleapis.com/maps/api/timezone/json?location=39.6034810,-119.6822510×tamp=1331161200&key=YOUR_API_KEY
{ "dstOffset" : 0, "rawOffset" : -28800, "status" : "OK", "timeZoneId" : "America/Los_Angeles", "timeZoneName" : "Pacific Standard Time" }
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 + "×tamp=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); } }); } }); }