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

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


当前回答

你可以使用geolocator.js轻松获得时区和更多…

它使用需要密钥的谷歌api。首先你配置geolocator

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

获取TimeZone,如果你有坐标:

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

示例输出:

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

定位,然后获得时区和更多

如果没有坐标,可以先定位用户位置。

下面的例子将首先尝试HTML5 Geolocation API来获取坐标。如果失败或被拒绝,它将通过Geo-IP查找获得坐标。最后,它将获得时区和更多…

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);
});

示例输出:

{
    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
}

其他回答

好的,这是没有正确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);

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());
    }
}

我们在Teleport刚刚开始开放我们的API,其中一个用例也是为坐标公开TZ信息。

例如,可以通过以下方式请求我们所有可用的TZ信息的坐标:

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"'

这将返回以下内容

{
  "_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"
}

在本例中,我使用./jq进行JSON解析。

对于我们这些使用Javascript并希望通过谷歌api从邮政编码获取时区的人来说,这里有一个方法。

通过地理定位获取lat/lng 通过这个参数获取时区 进入时区API。 此处使用Luxon进行时区转换。

注意:我的理解是,邮政编码在不同的国家并不是唯一的,所以这可能最适合在美国使用。

const googleMapsClient; // instantiate your client here
const zipcode = '90210'
const myDateThatNeedsTZAdjustment; // define your date that needs adjusting
// fetch lat/lng from google api by zipcode
const geocodeResponse = await googleMapsClient.geocode({ address: zipcode }).asPromise();
if (geocodeResponse.json.status === 'OK') {
  lat = geocodeResponse.json.results[0].geometry.location.lat;
  lng = geocodeResponse.json.results[0].geometry.location.lng;
} else {
  console.log('Geocode was not successful for the following reason: ' + status);
}

// prepare lat/lng and timestamp of profile created_at to fetch time zone
const location = `${lat},${lng}`;
const timestamp = new Date().valueOf() / 1000;
const timezoneResponse = await googleMapsClient
  .timezone({ location: location, timestamp: timestamp })
  .asPromise();

const timeZoneId = timezoneResponse.json.timeZoneId;
// adjust by setting timezone
const timezoneAdjustedDate = DateTime.fromJSDate(
  myDateThatNeedsTZAdjustment
).setZone(timeZoneId);

如果您想使用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);