Intereting Posts

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

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

благодаря

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

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

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

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

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

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

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

offset = direction * longitude * 24 / 360 

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

Я знаю, что это старо, но я потратил некоторое время на поиск этого ответа. Нашел что-то очень полезное. Google выполняет поиск по часовому поясу по длине / лат. 2500 в день (или 100 000 для бизнес-пользователей).

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

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

База данных мирового времени введите описание изображения здесь

Локальные / долготные данные многоугольника введите описание изображения здесь

Для областей на суше имеются карты шейп-файлов , которые были сделаны для временных интервалов базы данных 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://www.opensource.apple.com/source/TimeZoneData/

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

Вы можете увидеть изображение фигур по адресу 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&timestamp=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 + "&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); } }); } }); }