给定一个位置的经度和纬度,如何知道该位置的有效时区?

在大多数情况下,我们正在寻找IANA/Olson时区id,尽管有些服务可能只返回UTC偏移量或其他一些时区标识符。详细信息请阅读时区标签信息。


当前回答

我写了一个包https://github.com/ringsaturn/tzf支持获取时区在Go&Python和非常快:

package main

import (
    "fmt"

    "github.com/ringsaturn/tzf"
)

func main() {
    finder, err := tzf.NewDefaultFinder()
    if err != nil {
        panic(err)
    }
    fmt.Println(finder.GetTimezoneName(116.6386, 40.0786))
}

Python https://github.com/ringsaturn/tzfpy sample:

from tzfpy import get_tz

print(get_tz(121.4737, 31.2305))

Rust https://github.com/ringsaturn/tzf-rs样品:

use tzf_rs::DefaultFinder;

fn main() {
    let finder = DefaultFinder::new();

    print!("{:?}\n", DefaultFinder.get_tz_name(116.3883, 39.9289));
}

其他回答

如果您想使用geonames.org,请使用这段代码。(但是geonames.org有时很慢)

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;

 }

并将其用于:

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

function jsonpRequest(url, data) { let params = ""; for (let key in data) { if (data.hasOwnProperty(key)) { if (params.length == 0) { params += "?"; } else { params += "&"; } let encodedKey = encodeURIComponent(key); let encodedValue = encodeURIComponent(data[key]); params += encodedKey + "=" + encodedValue; } } let script = document.createElement('script'); script.src = url + params; document.body.appendChild(script); } function getLocation() { if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(showPosition); } else { x.innerHTML = "Geolocation is not supported by this browser."; } } let lat_ini=[]; let lon_ini=[]; function showPosition(position) { lat_ini= position.coords.latitude; lon_ini= position.coords.longitude; } ////delay time between lines function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } /////// function getGMT() { getfinalGMT() getLocation() async function sample() { await sleep(2000); let lat_str=lat_ini.toString(); let lng_str=" "+lon_ini.toString(); let url = "https://api.opencagedata.com/geocode/v1/json"; let data = { callback: "displayGMT", q: lat_str + lng_str, key: "fac4471073a347019196c1291e6a97d7" } jsonpRequest(url, data) } sample(); } let your_GMT=[]; function displayGMT(data) { your_GMT=(Number(data.results[0].annotations.timezone.offset_string)) console.log(your_GMT) } ///// function getfinalGMT() { let lat=document.getElementById("lat_id").value; let lng=document.getElementById("lng_id").value; let lat_str=lat.toString(); let lng_str=" "+lng.toString(); let url = "https://api.opencagedata.com/geocode/v1/json"; let data = { callback: "displayfinalGMT", q: lat + lng_str, key: "fac4471073a347019196c1291e6a97d7" } jsonpRequest(url, data) } let final_GMT=[]; function displayfinalGMT(data) { final_GMT=(Number(data.results[0].annotations.timezone.offset_string)) console.log(final_GMT) } /////clock const hourHand = document.querySelector('[data-hour-hand]') const minuteHand = document.querySelector('[data-minute-hand]') const secondHand = document.querySelector('[data-second-hand]') let dif_overall=[]; function setClock() { let gmt_diff=Number(your_GMT-final_GMT)/100 if (gmt_diff>12){ dif_overall=gmt_diff-12 } else{ dif_overall=gmt_diff } console.log(dif_overall) const currentDate = new Date() const secondsRatio = currentDate.getSeconds() / 60 const minutesRatio = (secondsRatio + currentDate.getMinutes()) / 60 const hoursRatio = (minutesRatio + currentDate.getHours() - dif_overall ) / 12 setRotation(secondHand, secondsRatio) setRotation(minuteHand, minutesRatio) setRotation(hourHand, hoursRatio) } function setRotation(element, rotationRatio) { element.style.setProperty('--rotation', rotationRatio * 360) } function activate_clock(){ setClock() setInterval(setClock, 1000) } *, *::after, *::before { box-sizing: border-box; } body { background: linear-gradient(to right, hsl(200, 100%, 50%), hsl(175, 100%, 50%)); display: flex; justify-content: center; align-items: center; min-height: 100vh; overflow: hidden; } .clock { width: 200px; height: 200px; background-color: rgba(255, 255, 255, .8); border-radius: 50%; border: 2px solid black; position: relative; } .clock .number { --rotation: 0; position: absolute; width: 100%; height: 100%; text-align: center; transform: rotate(var(--rotation)); font-size: 1.5rem; } .clock .number1 { --rotation: 30deg; } .clock .number2 { --rotation: 60deg; } .clock .number3 { --rotation: 90deg; } .clock .number4 { --rotation: 120deg; } .clock .number5 { --rotation: 150deg; } .clock .number6 { --rotation: 180deg; } .clock .number7 { --rotation: 210deg; } .clock .number8 { --rotation: 240deg; } .clock .number9 { --rotation: 270deg; } .clock .number10 { --rotation: 300deg; } .clock .number11 { --rotation: 330deg; } .clock .hand { --rotation: 0; position: absolute; bottom: 50%; left: 50%; border: 1px solid white; border-top-left-radius: 10px; border-top-right-radius: 10px; transform-origin: bottom; z-index: 10; transform: translateX(-50%) rotate(calc(var(--rotation) * 1deg)); } .clock::after { content: ''; position: absolute; background-color: black; z-index: 11; width: 15px; height: 15px; top: 50%; left: 50%; transform: translate(-50%, -50%); border-radius: 50%; } .clock .hand.second { width: 3px; height: 45%; background-color: red; } .clock .hand.minute { width: 7px; height: 40%; background-color: black; } .clock .hand.hour { width: 10px; height: 35%; background-color: black; } /* Background Styles Only */ @import url('https://fonts.googleapis.com/css?family=Raleway'); * { font-family: Raleway; } .side-links { position: absolute; top: 15px; right: 15px; } .side-link { display: flex; align-items: center; justify-content: center; text-decoration: none; margin-bottom: 10px; color: white; width: 180px; padding: 10px 0; border-radius: 10px; } .side-link-youtube { background-color: red; } .side-link-twitter { background-color: #1DA1F2; } .side-link-github { background-color: #6e5494; } .side-link-text { margin-left: 10px; font-size: 18px; } .side-link-icon { color: white; font-size: 30px; } <input type="text" id="lat_id" placeholder="lat"><br><br> <input type="text" id="lng_id" placeholder="lng"><br><br> <button class="text" onClick="getLocation()">Location</button> <button class="text" onClick="getGMT()"> GMT</button> <button class="text" onClick="activate_clock()"> Activate</button> <div class="clock"> <div class="hand hour" data-hour-hand></div> <div class="hand minute" data-minute-hand></div> <div class="hand second" data-second-hand></div> <div class="number number1">1</div> <div class="number number2">2</div> <div class="number number3">3</div> <div class="number number4">4</div> <div class="number number5">5</div> <div class="number number6">6</div> <div class="number number7">7</div> <div class="number number8">8</div> <div class="number number9">9</div> <div class="number number10">10</div> <div class="number number11">11</div> <div class="number number12">12</div> </div>

https://en.wikipedia.org/wiki/Great-circle_distance

下面是一个使用JSON数据的很好的实现: https://github.com/agap/llttz

public TimeZone nearestTimeZone(Location node) {
    double bestDistance = Double.MAX_VALUE;
    Location bestGuess = timeZones.get(0);

    for (Location current : timeZones.subList(1, timeZones.size())) {
        double newDistance = distanceInKilometers(node, current);

        if (newDistance < bestDistance) {
            bestDistance = newDistance;
            bestGuess = current;
        }
    }

    return java.util.TimeZone.getTimeZone(bestGuess.getZone());
}

  protected double distanceInKilometers(final double latFrom, final double lonFrom, final double latTo, final double lonTo) {
        final double meridianLength = 111.1;
        return meridianLength * centralAngle(latFrom, lonFrom, latTo, lonTo);
    }

    protected double centralAngle(final Location from, final Location to) {
        return centralAngle(from.getLatitude(), from.getLongitude(), to.getLatitude(), to.getLongitude());
    }

    protected double centralAngle(final double latFrom, final double lonFrom, final double latTo, final double lonTo) {
        final double latFromRad = toRadians(latFrom),
                lonFromRad = toRadians(lonFrom),
                latToRad   = toRadians(latTo),
                lonToRad   = toRadians(lonTo);

        final double centralAngle = toDegrees(acos(sin(latFromRad) * sin(latToRad) + cos(latFromRad) * cos(latToRad) * cos(lonToRad - lonFromRad)));

        return centralAngle <= 180.0 ? centralAngle : (360.0 - centralAngle);
    }

    protected double distanceInKilometers(final Location from, final Location to) {
        return distanceInKilometers(from.getLatitude(), from.getLongitude(), to.getLatitude(), to.getLongitude());
    }
}

我写了一个包https://github.com/ringsaturn/tzf支持获取时区在Go&Python和非常快:

package main

import (
    "fmt"

    "github.com/ringsaturn/tzf"
)

func main() {
    finder, err := tzf.NewDefaultFinder()
    if err != nil {
        panic(err)
    }
    fmt.Println(finder.GetTimezoneName(116.6386, 40.0786))
}

Python https://github.com/ringsaturn/tzfpy sample:

from tzfpy import get_tz

print(get_tz(121.4737, 31.2305))

Rust https://github.com/ringsaturn/tzf-rs样品:

use tzf_rs::DefaultFinder;

fn main() {
    let finder = DefaultFinder::new();

    print!("{:?}\n", DefaultFinder.get_tz_name(116.3883, 39.9289));
}

好的,这是没有正确NTP时间的短版本:

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;

}

并将其用于:

GeoPoint gp = new GeoPoint(39.6034810,-119.6822510);
long Current_TimeZone_Time_l = get_time_zone_time_l(gp);