ti-enxame.com

Como obter um fuso horário de um local usando coordenadas de latitude e longitude?

Há muitas perguntas no StackOverflow sobre como resolver um fuso horário de um local. Este wiki da comunidade é uma tentativa de consolidar todas as respostas válidas.

Por favor, atualize minha resposta, ou adicione a sua como achar melhor.

A pergunta
Dada a latitude e a longitude de um local, como saber qual fuso horário está em vigor nesse local?

Na maioria dos casos, estamos procurando um ID de fuso horário IANA/Olson, embora alguns serviços possam retornar apenas um deslocamento UTC ou algum outro identificador de fuso horário. Por favor, leia o info de tag de fuso horário para mais detalhes.

260
Matt Johnson

Serviços da Web do Local do Fuso Horário

Dados brutos de limite de fuso horário

Os projetos a seguir foram fontes de dados de limite de fuso horário, mas não são mais mantidos ativamente.

Implementações off-line de geolocalização de fuso horário

Implementações que usam os dados do Timezone Boundary Builder

Implementações que usam os dados mais antigos do tz_world

Bibliotecas que chamam um dos serviços da Web

  • fuso horário - gem Ruby que chama GeoNames
  • AskGeo tem suas próprias bibliotecas para chamadas de Java ou .Net
  • GeoNames tem bibliotecas de clientes para quase tudo

Outras ideias

Por favor atualize esta lista se você souber de alguma outra

Além disso, observe que a abordagem de cidade mais próxima pode não produzir o resultado "correto", apenas uma aproximação.

Conversão para Windows Zones

A maioria dos métodos listados retornará um ID de fuso horário da IANA. Se você precisar converter para um fuso horário do Windows para uso com a classe TimeZoneInfo no .NET, use a biblioteca TimeZoneConverter .

Não use zone.tab

O banco de dados tz inclui um arquivo chamado zone.tab . Esse arquivo é usado principalmente para apresentar uma lista de fusos horários para um usuário escolher. Inclui as coordenadas de latitude e longitude do ponto de referência para cada fuso horário. Isso permite que um mapa seja criado destacando esses pontos. Por exemplo, veja o mapa interativo mostrado em a página inicial do fuso horário .

Embora seja tentador usar esses dados para resolver o fuso horário de coordenadas de latitude e longitude, considere que esses são pontos - e não limites. O melhor que se poderia fazer seria determinar o ponto mais próximo , que em muitos casos não será o ponto correto.

Considere o seguinte exemplo:

 Time Zone Example Art

Os dois quadrados representam diferentes fusos horários, onde o ponto preto em cada quadrado é o local de referência, como o que pode ser encontrado em zone.tab. O ponto azul representa o local para o qual estamos tentando encontrar um fuso horário. Claramente, este local está dentro da zona laranja à esquerda, mas se olharmos apenas para a distância mais próxima do ponto de referência, ele será resolvido para a zona esverdeada à direita.

349
Matt Johnson

Que tal esta solução para node.js https://github.com/mattbornski/tzwhere

E sua contraparte em Python: https://github.com/pegler/pytzwhere

9
zbinsd

Nós em Teleport apenas começamos abrindo nossas API's e um dos usuários também está expondo informações de TZ para coordenadas.

Por exemplo, pode-se solicitar todas as informações de TZ disponíveis para coordenadas da seguinte maneira:

curl -s https://api.teleport.org/api/locations/59.4372,24.7453/?embed=location:nearest-cities/location:nearest-city/city:timezone/tz:offsets-now | jq '._embedded."location:nearest-cities"[0]._embedded."location:nearest-city"._embedded."city:timezone"'

Isso retornaria o seguinte

{
  "_embedded": {
    "tz:offsets-now": {
      "_links": {
        "self": {
          "href": "https://api.teleport.org/api/timezones/iana:Europe%2FTallinn/offsets/?date=2015-09-07T11%3A20%3A09Z"
        }
      },
      "base_offset_min": 120,
      "dst_offset_min": 60,
      "end_time": "2015-10-25T01:00:00Z",
      "short_name": "EEST",
      "total_offset_min": 180,
      "transition_time": "2015-03-29T01:00:00Z"
    }
  },
  "_links": {
    "self": {
      "href": "https://api.teleport.org/api/timezones/iana:Europe%2FTallinn/"
    },
    "tz:offsets": {
      "href": "https://api.teleport.org/api/timezones/iana:Europe%2FTallinn/offsets/{?date}",
      "templated": true
    },
    "tz:offsets-now": {
      "href": "https://api.teleport.org/api/timezones/iana:Europe%2FTallinn/offsets/?date=2015-09-07T11%3A20%3A09Z"
    }
  },
  "iana_name": "Europe/Tallinn"
}

Para o exemplo, usei ./jq para análise JSON.

6
Joonathan

Veja como você pode usar o editor de scripts do Google para obter o timezoneName e o timeZoneId dentro de um gsheet.

Etapa 1. Obtenha uma chave de API para a API de fuso horário do Google

Etapa 2. Crie uma nova planilha. Abaixo do menu 'ferramentas', clique em 'editor de scripts'. Adicione o seguinte código:

function getTimezone(lat, long) {  
  var apiKey = 'INSERTAPIKEYHERE'
  var url = 'https://maps.googleapis.com/maps/api/timezone/json?location=' + lat + ',' + long + '&timestamp=1331161200&key=' + apiKey 
  var response = UrlFetchApp.fetch(url);
  var data = JSON.parse(response.getContentText());
  return data["timeZoneName"];
}

Passo 3. Salve e publique sua função getTimezone() e use-a conforme mostrado na imagem acima.

2
Stiño

Você pode usar geolocator.js para obter facilmente fuso horário e muito mais ...

Ele usa APIs do Google que exigem uma chave. Então, primeiro você configura o geolocator:

geolocator.config({
    language: "en",
    google: {
        version: "3",
        key: "YOUR-GOOGLE-API-KEY"
    }
});

Obtenha o fuso horário se você tiver as coordenadas:

geolocator.getTimeZone(options, function (err, timezone) {
    console.log(err || timezone);
});

Exemplo de saída:

{
    id: "Europe/Paris",
    name: "Central European Standard Time",
    abbr: "CEST",
    dstOffset: 0,
    rawOffset: 3600,
    timestamp: 1455733120
}

Localize e obtenha TimeZone e mais

Se você não tiver as coordenadas, poderá localizar a posição do usuário primeiro.

O exemplo abaixo tentará primeiro a API de geolocalização do HTML5 para obter as coordenadas. Se falhar ou for rejeitado, obterá as coordenadas por meio da pesquisa Geo-IP. Finalmente, ele irá obter o fuso horário e muito mais ...

var options = {
    enableHighAccuracy: true,
    timeout: 6000,
    maximumAge: 0,
    desiredAccuracy: 30,
    fallbackToIP: true, // if HTML5 fails or rejected
    addressLookup: true, // this will get full address information
    timezone: true,
    map: "my-map" // this will even create a map for you
};
geolocator.locate(options, function (err, location) {
    console.log(err || location);
});

Exemplo de saída:

{
    coords: {
        latitude: 37.4224764,
        longitude: -122.0842499,
        accuracy: 30,
        altitude: null,
        altitudeAccuracy: null,
        heading: null,
        speed: null
    },
    address: {
        commonName: "",
        street: "Amphitheatre Pkwy",
        route: "Amphitheatre Pkwy",
        streetNumber: "1600",
        neighborhood: "",
        town: "",
        city: "Mountain View",
        region: "Santa Clara County",
        state: "California",
        stateCode: "CA",
        postalCode: "94043",
        country: "United States",
        countryCode: "US"
    },
    formattedAddress: "1600 Amphitheatre Parkway, Mountain View, CA 94043, USA",
    type: "ROOFTOP",
    placeId: "ChIJ2eUgeAK6j4ARbn5u_wAGqWA",
    timezone: {
        id: "America/Los_Angeles",
        name: "Pacific Standard Time",
        abbr: "PST",
        dstOffset: 0,
        rawOffset: -28800
    },
    flag: "//cdnjs.cloudflare.com/ajax/libs/flag-icon-css/2.3.1/flags/4x3/us.svg",
    map: {
        element: HTMLElement,
        instance: Object, // google.maps.Map
        marker: Object, // google.maps.Marker
        infoWindow: Object, // google.maps.InfoWindow
        options: Object // map options
    },
    timestamp: 1456795956380
}
2
Onur Yıldırım

usando latitude e longitude obter fuso horário da localização atual abaixo código funcionou para mim

String data = null;         
LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
Location ll = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
double lat = 0,lng = 0;
if(ll!=null){
    lat=ll.getLatitude();
    lng=ll.getLongitude();
}
System.out.println(" Last known location of device  == "+lat+"    "+lng);

InputStream iStream = null; 
HttpURLConnection urlConnection = null;
try{
    timezoneurl = timezoneurl+"location=22.7260783,75.8781553&timestamp=1331161200";                    
    // timezoneurl = timezoneurl+"location="+lat+","+lng+"&timestamp=1331161200";

    URL url = new URL(timezoneurl);                
    // Creating an http connection to communicate with url 
    urlConnection = (HttpURLConnection) url.openConnection(); 

    // Connecting to url 
    urlConnection.connect();                

    // Reading data from url 
    iStream = urlConnection.getInputStream();

    BufferedReader br = new BufferedReader(new InputStreamReader(iStream));

    StringBuffer sb  = new StringBuffer();
    String line = "";
    while( ( line = br.readLine())  != null){
        sb.append(line);
    }
    data = sb.toString();
    br.close();

}catch(Exception e){
    Log.d("Exception while downloading url", e.toString());
}finally{
    try {
        iStream.close();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    urlConnection.disconnect();
}

try {
    if(data!=null){
        JSONObject jobj=new JSONObject(data);
        timezoneId = jobj.getString("timeZoneId");

        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        format.setTimeZone(TimeZone.getTimeZone(timezoneId));

        Calendar cl = Calendar.getInstance(TimeZone.getTimeZone(timezoneId));
        System.out.println("time zone id in Android ==  "+timezoneId);

        System.out.println("time zone of  device in Android == "+TimeZone.getTimeZone(timezoneId));
        System.out.println("time fo device in Android "+cl.getTime());
    }
} catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
0
user4042384

Ok, aqui está a versão curta sem corrigir NTP Hora:

String get_xml_server_reponse(String server_url){

URL xml_server = null;

String xmltext = "";

InputStream input;


try {
    xml_server = new URL(server_url);


    try {
        input = xml_server.openConnection().getInputStream();


        final BufferedReader reader = new BufferedReader(new InputStreamReader(input));
        final StringBuilder sBuf = new StringBuilder();

        String line = null;
        try {
            while ((line = reader.readLine()) != null) 
            {
                sBuf.append(line);
            }
           } 
        catch (IOException e) 
          {
                Log.e(e.getMessage(), "XML parser, stream2string 1");
          } 
        finally {
            try {
                input.close();
                }
            catch (IOException e) 
            {
                Log.e(e.getMessage(), "XML parser, stream2string 2");
            }
        }

        xmltext =  sBuf.toString();

    } catch (IOException e1) {

            e1.printStackTrace();
        }


    } catch (MalformedURLException e1) {

      e1.printStackTrace();
    }

 return  xmltext;

} 


long get_time_zone_time_l(GeoPoint gp){


        String raw_offset = "";
        String dst_offset = "";

        double Longitude = gp.getLongitudeE6()/1E6;
        double Latitude = gp.getLatitudeE6()/1E6;

        long tsLong = System.currentTimeMillis()/1000;


        if (tsLong != 0)
        {

        // https://maps.googleapis.com/maps/api/timezone/xml?location=39.6034810,-119.6822510&timestamp=1331161200&sensor=false

        String request = "https://maps.googleapis.com/maps/api/timezone/xml?location="+Latitude+","+ Longitude+ "&timestamp="+tsLong +"&sensor=false";

        String xmltext = get_xml_server_reponse(request);

        if(xmltext.compareTo("")!= 0)
        {

         int startpos = xmltext.indexOf("<TimeZoneResponse");
         xmltext = xmltext.substring(startpos);



        XmlPullParser parser;
        try {
            parser = XmlPullParserFactory.newInstance().newPullParser();


             parser.setInput(new StringReader (xmltext));

             int eventType = parser.getEventType();  

             String tagName = "";


             while(eventType != XmlPullParser.END_DOCUMENT) {
                 switch(eventType) {

                     case XmlPullParser.START_TAG:

                           tagName = parser.getName();

                         break;


                     case XmlPullParser.TEXT :


                        if  (tagName.equalsIgnoreCase("raw_offset"))
                          if(raw_offset.compareTo("")== 0)                               
                            raw_offset = parser.getText();  

                        if  (tagName.equalsIgnoreCase("dst_offset"))
                          if(dst_offset.compareTo("")== 0)
                            dst_offset = parser.getText();  


                        break;   

                 }

                 try {
                        eventType = parser.next();
                    } catch (IOException e) {

                        e.printStackTrace();
                    }

                }

                } catch (XmlPullParserException e) {

                    e.printStackTrace();
                    erg += e.toString();
                }

        }      

        int ro = 0;
        if(raw_offset.compareTo("")!= 0)
        { 
            float rof = str_to_float(raw_offset);
            ro = (int)rof;
        }

        int dof = 0;
        if(dst_offset.compareTo("")!= 0)
        { 
            float doff = str_to_float(dst_offset);
            dof = (int)doff;
        }

        tsLong = (tsLong + ro + dof) * 1000;


        }


  return tsLong;

}

E use-o com:

GeoPoint gp = new GeoPoint(39.6034810,-119.6822510);
long Current_TimeZone_Time_l = get_time_zone_time_l(gp);
0
Ingo
  1. Existem várias fontes on-line que possuem dados geojson para fusos horários ( aqui está um , aqui outro)

  2. Use uma biblioteca de geometria para criar objetos de polígonos a partir das coordenadas geojson ( bem formado [python], GEOS [c ++], JTS [ Java], NTS [.net]).

  3. Converta seu lat/lng em um objeto de ponto (no entanto, sua biblioteca representa isso) e verifique se ele intercepta o polígono de fuso horário.

    from shapely.geometry import Polygon, Point
    
    def get_tz_from_lat_lng(lat, lng):
        for tz, geojson in timezones.iteritems():
            coordinates = geojson['features'][0]['geometry']['coordinates']
            polygon = Polygon(coordinates)
            point = Point(lng, lat)
            if polygon.contains(point):
                return tz
    
0
jtschoonhoven

Se você quiser usar geonames.org, use este código. (Mas geonames.org é muito lento às vezes)

String get_time_zone_time_geonames(GeoPoint gp){


        String erg = "";

        double Longitude = gp.getLongitudeE6()/1E6;
        double Latitude = gp.getLatitudeE6()/1E6;



        String request = "http://ws.geonames.org/timezone?lat="+Latitude+"&lng="+ Longitude+ "&style=full";

        URL time_zone_time = null;

        InputStream input;
       // final StringBuilder sBuf = new StringBuilder();


        try {
            time_zone_time = new URL(request);


        try {
            input = time_zone_time.openConnection().getInputStream();


        final BufferedReader reader = new BufferedReader(new InputStreamReader(input));
            final StringBuilder sBuf = new StringBuilder();

            String line = null;
            try {
                while ((line = reader.readLine()) != null) {
                    sBuf.append(line);
                }
            } catch (IOException e) {
                    Log.e(e.getMessage(), "XML parser, stream2string 1");
            } finally {
                try {
                    input.close();
                } catch (IOException e) {
                    Log.e(e.getMessage(), "XML parser, stream2string 2");
                }
            }




             String xmltext = sBuf.toString();


             int startpos = xmltext.indexOf("<geonames");
             xmltext = xmltext.substring(startpos);



            XmlPullParser parser;
            try {
                parser = XmlPullParserFactory.newInstance().newPullParser();


            parser.setInput(new StringReader (xmltext));

            int eventType = parser.getEventType();  

            String tagName = "";

            while(eventType != XmlPullParser.END_DOCUMENT) {
                switch(eventType) {

                    case XmlPullParser.START_TAG:

                          tagName = parser.getName();

                        break;


                    case XmlPullParser.TEXT :


                        if  (tagName.equalsIgnoreCase("time"))
                          erg = parser.getText();  


                    break;   

                }

                try {
                    eventType = parser.next();
                } catch (IOException e) {

                    e.printStackTrace();
                }

            }

            } catch (XmlPullParserException e) {

                e.printStackTrace();
                erg += e.toString();
            }



            } catch (IOException e1) {

                e1.printStackTrace();
            }


            } catch (MalformedURLException e1) {

                e1.printStackTrace();
            }





        return erg;

 }

E use-o com:

GeoPoint gp = new GeoPoint(39.6034810,-119.6822510);
String Current_TimeZone_Time = get_time_zone_time_geonames(gp);
0
Ingo

É realmente importante reconhecer que isso é um problema mais complicado do que a maioria suspeitaria. Na prática, muitos de nós também estão dispostos a aceitar um código de trabalho que funcione para "tantos casos quanto possível", onde pelo menos seus problemas fatais podem ser identificados e minimizados coletivamente. Então eu postei isso com tudo isso e o espírito do OP em mente. Finalmente, para valor prático para outras pessoas que estão tentando converter GPS para fuso horário com o objetivo final de ter um objeto de tempo sensível à localização (e mais importante para ajudar a melhorar a qualidade das implementações médias com objetos de tempo que seguem neste wiki) aqui o que eu gero em Python (por favor sinta-se livre para editar):

import pytz
from datetime import datetime
from tzwhere import tzwhere

def timezoned_unixtime(latitude, longitude, dt):
    tzw = tzwhere.tzwhere()
    timezone_str = tzw.tzNameAt(latitude, longitude)
    timezone = pytz.timezone(timezone_str)
    timezone_aware_datetime = timezone.localize(dt, is_dst=None)
    unix_time = (timezone_aware_datetime - datetime(1970, 1, 1, tzinfo=pytz.utc)).total_seconds()
    return unix_time

dt = datetime(year=2017, month=1, day=17, hour=12, minute=0, second=0)
print timezoned_unixtime(latitude=40.747854, longitude=-74.004733, dt=dt)
0
legel