web-dev-qa-db-ja.com

Geonames.orgなどのWebサービスを使用せずに、緯度/経度からタイムゾーンを決定する

webサービスを使用せずにポイントのタイムゾーン(緯度/経度)を決定する可能性はありますか? Geonames.orgは私が使用するには十分に安定していません:(PHPで動作させるにはこれが必要です。

ありがとう

49
Jacek Francuz

私はしばらく前にこの問題を抱えていて、アダムが示唆したとおりにした。

  • 都市のデータベース をgeonames.orgからダウンロードします
  • コンパクトな緯度経度に変換->タイムゾーンリスト
  • R-Tree 実装を使用して、指定された座標に最も近い都市(またはそのタイムゾーン)を効率的に検索します。

IIRCは、Rツリーにデータを取り込むのに1秒もかかりませんでしたが、1秒あたり数千の検索を実行できました(両方とも5年前のPC)。

54

結果はどの程度正確でなければなりませんか?概算で十分な場合は、オフセットを自分で計算します。

offset = direction * longitude * 24 / 360

ここで、方向は東の場合は1、西の場合は-1、経度は(-180,180)です

別のプロジェクトに取り組んでいるときにこの問題に遭遇し、非常に深く調べました。私は、既存のソリューションのすべてが主要な点で欠けていることを発見しました。

GeoNamesデータをダウンロードし、空間インデックスを使用して最も近いポイントを検索することは間違いなくオプションであり、多くの場合正しい結果が得られますが、クエリポイントが時間の反対側にある場合は簡単に失敗する可能性がありますデータベースの最も近い点からのゾーン境界。

より正確な方法は、タイムゾーンのデジタルマップを使用し、特定のクエリポイントを含むマップ内のポリゴンを検​​索するコードを記述することです。ありがたいことに、 http://efele.net/maps/tz/world/ (メンテナンスされていません anymore )で利用可能な世界のタイムゾーンの優れたマップがあります。効率的なクエリエンジンを作成するには、次のことが必要です。

  • ESRIシェープファイル形式を解析して、有用な内部表現にします。
  • 特定のクエリポイントが特定のポリゴン内にあるかどうかをテストするには、ポリゴン内のポイントコードを記述します。
  • ポリゴンデータの上に効率的な空間インデックスを作成して、すべてのポリゴンをチェックして、含まれているポリゴンを見つける必要がないようにします。
  • ポリゴンに含まれていないクエリを処理します(例:海洋)。このような場合、特定の距離まで最も近いポリゴンに「スナップ」し、外洋の「自然な」タイムゾーン(経度のみで決定されるタイムゾーン)に戻す必要があります。これを行うには、クエリポイントとポリゴンのラインセグメント間の距離を計算するコードが必要です(緯度と経度はユークリッド座標系ではないため、これは重要です)。また、空間インデックスは潜在的にポリゴンを含むだけでなく、近くのポリゴンを返すことができます。

これらはそれぞれ、独自のStack Overflowの質問/回答ページに値します。

そこにある既存のソリューションはどれも私のニーズを満たしていないと結論付けた後、私は独自のソリューションを作成し、ここで利用可能にしました

http://askgeo.com

AskGeoはデジタルマップを使用し、高度に最適化された空間インデックスを使用して、1つのスレッドでコンピューター上で毎秒10,000を超えるクエリを実行できます。また、スレッドセーフなので、さらに高いスループットが可能です。これは深刻なコードであり、開発に長い時間がかかったため、商用ライセンスで提供しています。

これはJavaで記述されているため、PHPで使用するには、以下を使用する必要があります。

http://php-Java-bridge.sourceforge.net/doc/how_it_works.php

また、賞金のために移植することもできます。価格の詳細および詳細なドキュメントについては、 http://askgeo.com を参照してください。

これが役に立つことを願っています。確かに、私が取り組んでいたプロジェクトに役立ちました。

10
James D

私はこれが古いことを知っていますが、私はこの答えを探すのに時間を費やしました。非常に便利なものが見つかりました。 Googleは、ロング/ラテによるタイムゾーンルックアップを行います。 無料利用枠はなくなりました :-/

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

8
Jeffrey Vdovjak

タイムゾーンのポリゴンを知っていれば、特定の緯度/経度が内部にあるかどうかを確認できます。

ワールドタイムゾーンデータベース enter image description here

緯度/経度のポリゴンデータ enter image description here

5
daniellmb

陸上のエリアには、tz(Olson)データベースのタイムゾーン用に作成されたいくつかの shapefileマップ があります。それらはtzデータベース自体ほど定期的に更新されませんが、それは素晴らしい出発点であり、ほとんどの目的で非常に正確であるようです。

5
Tim Parenti

これはどう ?

// 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') ;
3
j-bin

これを行うために、小さなJavaクラスを作成しました。PHPに簡単に翻訳できます。データベースはコード自体に埋め込まれています。22kmの精度です。

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への翻訳は簡単だと思います。

2
Tim Cooper

別の解決策は、タイムゾーンを持つ都市のテーブルをインポートし、Haversine式を使用して、座標に関連するそのテーブル内の最も近い都市を見つけることです。完全な説明をここに投稿しました: 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 formula)

1
MikeM

残念なことに、タイムゾーンは、いくつかの単純な機能に対して十分に規則的ではありません。 Wikipedia-Time Zone の地図をご覧ください

ただし、非常に大まかな近似値を計算できます。1時間の差は、経度15度(360/24)に相当します。

1
MillKa

これが役に立つかどうかはわかりませんが、タイムゾーンの形状のデータベースを構築しました(北米のみ)。これは、国境だけでなく夏時間の遵守のために、骨の折れるほど正確で最新のものです。また、非公式の例外にも対応します。したがって、特定の場所の一連の図形を照会すると、その場所に適用される複数の図形が返され、その時期に適切な図形を選択できます。

http://OnTimeZone.com/OnTimeZone_shapes.gif で図形の画像を見ることができます。青い図形は夏時間を監視していないエリアの周りにあり、マゼンタは夏時間を監視しているエリアの周りにあり、ネオングリーンの図形(そのズームレベルで小さくて見づらい)は公式のタイムゾーンからの非公式な偏差があるエリアにあります。 OnTimeZone.comサイトで入手可能な詳細については、詳細をご覧ください。

OnTimeZone.comでダウンロード可能なデータは、非営利目的での使用は無料です。ダウンロードできないシェイプデータは、商用ライセンスで利用できます。

1
Steve

ここで提供されるタイムゾーン境界を使用できます。

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

5桁の郵便番号をタイムゾーンに一致させるデータと、DSTおよび非DST期間中の各タイムゾーンのUTCオフセットを決定するデータをダウンロードしました。

次に、最初の3桁を共有するすべての郵便番号は非常に近いため、データを単純化して郵便番号の最初の3桁のみを考慮しました。 3桁は一意のメール配信センターを識別します。

結果のJsonファイルでは、現在DSTの対象であるかどうかを判断する必要があり、おそらくあちこちで不正確な部分があります。しかし、非常にコンパクトでクエリが簡単な、非常に優れたローカルソリューションです。

ここにあります: https://Gist.github.com/benjiwheeler/8aced8dac396c2191cf

0
Ben Wheeler
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);

                    }
                });

            }
        });
    }
0
Ummar farook P

このプロジェクト OpenStreetMapのデータからシェープファイルを作成し、それを処理する複数のライブラリにリンクします。 PHPを見ることができます https://github.com/minube/geo-timezone

0
vwvw

geocoder.ca を使用します

北アメリカの任意の場所を入力し、jsonまたはjsonpでジオコード、市外局番、タイムゾーンを出力します。

例: http://geocoder.ca/1600%20pennsylvania%20avenue,Washington,DC

市外局番:(202)時間帯:アメリカ/ニューヨーク

ジョンソン:

{"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"}
0
Ervin Ruci

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"
}
0
Sheena Singla