Déterminez le fuseau horaire à partir de la latitude / longitude sans utiliser des services web comme Geonames.org

est-il possible de déterminer le fuseau horaire du point (lat/lon) sans utiliser les services web? Geonames.org n'est pas assez stable pour que je l'utilise :( j'en ai besoin pour fonctionner en PHP.

Merci

48
demandé sur Matt Johnson 2011-04-07 20:45:16

16 réponses

j'ai eu ce problème il y a quelque temps et j'ai fait exactement ce qu'adam a suggéré:

  • Téléchargez la base de données des villes à partir geonames.org
  • convertissez-le en Lat/lon compact - > liste des fuseaux horaires
  • utilisez un R-Tree implémentation pour rechercher efficacement la ville la plus proche (ou plutôt, son fuseau horaire) à une coordonnée donnée

autant que je me souvienne il a fallu moins d'une seconde pour peupler L'arbre R, et il pourrait alors effectuer des milliers de recherches par seconde (tous les deux sur un PC de 5 ans).

54
répondu Michael Borgwardt 2011-04-07 17:09:17

vos résultats doivent-ils être exacts? Si une estimation approximative est suffisante, calculez vous-même le décalage:

offset = direction * longitude * 24 / 360

où la direction est 1 pour l'est, -1 pour l'ouest, et la longitude est en (-180,180)

12
répondu Christian Stade-Schuldt 2013-10-30 23:02:02

j'ai rencontré ce problème en travaillant sur un autre projet et le regarda dans les très profondément. J'ai constaté que toutes les solutions existantes manquaient de façon importante.

Télécharger les données GeoNames et utiliser un index spatial pour chercher le point le plus proche est certainement une option, et il donnera le bon résultat une grande partie du temps, mais il peut facilement échouer si un point de requête est du mauvais côté d'une frontière de fuseau horaire à partir du point le plus proche dans la base de données.

Une méthode plus précise consiste à utiliser une carte numérique des fuseaux horaires et à écrire du code pour trouver le polygone de cette carte qui contient un point de requête. Heureusement, il y a une excellente carte des fuseaux horaires du monde disponible à http://efele.net/maps/tz/world / . Pour écrire un moteur de requête efficace, vous devez:

  • analyse le format shapefile ESRI en une représentation interne utile.
  • Écrire un code point-en-polygone pour vérifier si un point de requête donné se trouve dans un polygone donné.
  • écrivez un index spatial efficace au-dessus des données du polygone afin que vous n'ayez pas besoin de vérifier chaque polygone pour trouver celui qui contient.
  • traite les requêtes qui ne sont pas contenues dans un polygone (par exemple, dans l'océan). Dans de tels cas, vous devriez "snap to" Le Polygone le plus proche jusqu'à une certaine distance, et revenir au fuseau horaire "naturel" (celui déterminé par la seule longitude) en haute mer. Pour ce faire, vous aurez besoin de code pour calculer la distance entre un point de requête et un segment de ligne d'un polygone (ce qui n'est pas trivial puisque la latitude et la longitude sont un système de coordonnées non euclidienne), et votre index spatial devra être en mesure de retourner les polygones voisins, et pas seulement potentiellement contenant des polygones.

chacun d'eux est digne de sa propre page de questions/réponses.

après avoir conclu qu'aucune des solutions existantes là-bas ne répond à mes besoins, j'ai écrit ma propre solution et l'ai rendue disponible ici:

http://askgeo.com

AskGeo utilise une carte numérique et dispose d'un index spatial hautement optimisé qui permet d'exécuter plus de 10.000 requêtes par seconde sur mon ordinateur dans un seul thread. Et c'est sans danger, donc un débit encore plus élevé est certainement possible. C'est une grave un morceau de code, et il nous a fallu beaucoup de temps pour le développer, donc nous l'offrons sous licence commerciale.

il est écrit en Java, donc l'utiliser en PHP impliquerait d'utiliser:

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

Nous sommes aussi ouverts à portage pour un bounty. Pour plus de détails sur le prix, et pour la documentation détaillée, voir http://askgeo.com .

j'espère que c'est utile. C'était certainement utile pour le projet sur lequel je travaillais.

10
répondu James D 2012-05-08 12:59:20

je sais que c'est vieux, mais j'ai passé du temps à chercher cette réponse. Trouvé quelque chose de très utile. Google fait des recherches de fuseau horaire par long / lat. Limite de 2 500 par jour (ou 100 000 pour les utilisateurs commerciaux).

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

8
répondu Jeffrey Vdovjak 2013-01-27 06:50:56

vous devriez pouvoir, si vous connaissez le polygone du fuseau horaire pour voir si un lat/lon donné est à l'intérieur.

Temps Du Monde La Zone De La Base De Données enter image description here

Données Polygonales De Latitude/Longitude enter image description here

5
répondu daniellmb 2011-04-07 16:59:55

pour les zones sur la terre, Il ya quelques shapefile maps qui ont été faites pour les fuseaux horaires de la base de données TZ (Olson). Ils ne sont pas mis à jour aussi régulièrement que la base de données tz elle-même, mais c'est un excellent point de départ et semble être très précis pour la plupart des fins.

5
répondu Tim Parenti 2012-01-21 18:25:30

et ça ?

// 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
répondu j-bin 2013-03-20 21:58:24

j'ai écrit une petite classe de Java pour faire ça. Il pourrait être facilement traduit en PHP. La base de données est intégrée dans le code lui-même. Il est précis à 22km.

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

le code entier est essentiellement des trucs comme ça:

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

... donc je suppose qu'une traduction en PHP serait facile.

2
répondu Tim Cooper 2013-12-03 20:03:17

malheureusement, les fuseaux horaires ne sont pas assez réguliers pour une simple fonction. Voir la carte dans Wikipedia-fuseau horaire

cependant, une approximation très grossière peut être calculée: 1 heure de différence correspond à 15 degrés de longitude (360 / 24).

1
répondu MillKa 2011-04-07 16:53:48

une autre solution est d'importer une table des villes avec des fuseaux horaires et ensuite d'utiliser la formule Haversine pour trouver la ville la plus proche dans cette table, en rapport avec vos coordonnées. J'ai posté une description complète ici: http://sylnsr.blogspot.com/2012/12/find-nearest-location-by-latitude-and.html

pour un exemple de chargement de données dans MySQL, j'ai posté un exemple ici (avec des sources pour télécharger un petit dump de données): http://sylnsr.blogspot.com/2012/12/load-timezone-data-by-city-and-country.html

notez que l'exactitude de la recherche sera basée sur l'exhaustivité de vos données de recherche.

crédits et références: MySQL Great Circle Distance (formule de Haversine)

1
répondu Michael Mügge 2017-05-23 12:10:51

vous pouvez utiliser les limites des fuseaux horaires, à condition que:

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

1
répondu Mikhail Krasnorutsky 2013-02-13 18:32:41

pas sûr que ce soit utile ou pas, mais j'ai construit une base de données de formes de fuseaux horaires (pour L'Amérique du Nord seulement), qui est minutieusement précise et actuelle non seulement pour les frontières, mais aussi pour l'observation de l'heure d'été. Aussi des formes pour des exceptions non officielles. Donc vous pouvez interroger l'ensemble des formes pour un endroit donné pourrait retourner plusieurs formes qui s'appliquent à cet endroit, et choisir la bonne pour la période de l'année.

vous pouvez voir une image des formes à http://OnTimeZone.com/OnTimeZone_shapes.gif . Les formes bleues sont autour des zones qui n'observent pas l'heure d'été, magenta forme ceux qui observent l'heure d'hiver, et les formes vertes néons (petites et difficiles à voir à ce niveau de zoom) sont pour les zones avec une déviation officieuse du fuseau horaire officiel. Beaucoup plus de détails sur celui disponible à la OnTimeZone.com site.

les données peuvent être téléchargées à l'adresse suivante: OnTimeZone.com est gratuit pour une utilisation non commerciale. Les données de forme, ce qui n'est pas disponible pour le téléchargement est disponible pour la licence commerciale.

1
répondu Steve 2014-01-10 01:09:56

j'ai téléchargé des données qui concordent les codes zip à cinq chiffres avec les fuseaux horaires, et des données qui déterminent le décalage UTC pour chaque fuseau horaire durant les périodes de L'heure avancée et les périodes autres que l'heure avancée.

ensuite j'ai simplifié les données pour ne considérer que les trois premiers chiffres du code postal, puisque tous les codes postaux qui partagent les trois premiers chiffres sont très proches l'un de l'autre; les trois chiffres identifient un centre unique de distribution du courrier.

le fichier JSON résultant vous oblige à décidez si vous êtes ou non assujetti à L'heure actuelle à L'heure actuelle, et il a probablement une certaine inexactitude ici et là. Mais c'est une très bonne solution locale qui est très compacte et simple à interroger.

: https://gist.github.com/benjiwheeler/8aced8dac396c2191cf0

0
répondu Ben Wheeler 2015-06-19 21:35:34

j'utilise géocodeur.ca

d'Entrée de n'importe quel emplacement en Amérique du Nord, Sortie géocodes, les indicatifs de zone et le fuseau horaire en json ou jsonp.

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

Indicatif Régional: (202) Fuseau Horaire: Amérique / 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"}
0
répondu Ervin Ruci 2015-11-23 19:33:16

vous pouvez utiliser l'api Google Timezone. 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
répondu Sheena Singla 2016-11-02 05:42:05
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
répondu Ummar farook P 2017-01-07 06:43:25