给定一个位置的经度和纬度,如何知道该位置的有效时区?
在大多数情况下,我们正在寻找IANA/Olson时区id,尽管有些服务可能只返回UTC偏移量或其他一些时区标识符。详细信息请阅读时区标签信息。
给定一个位置的经度和纬度,如何知道该位置的有效时区?
在大多数情况下,我们正在寻找IANA/Olson时区id,尽管有些服务可能只返回UTC偏移量或其他一些时区标识符。详细信息请阅读时区标签信息。
当前回答
如果您想使用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);
其他回答
对于我们这些使用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);
时区位置Web服务
谷歌映射时区API 必应地图时区API Azure地图时区API GeoNames时区API TimeZoneDB API AskGeo -商业(但可以说比GeoNames更准确) 地理车库时区API -商业,专注于航海时区。
原始时区边界数据
Timezone Boundary Builder -从OpenStreetMaps地图数据中构建时区形状文件。包括海岸线附近的领海。
以下项目以前是时区边界数据的来源,但不再积极维护。
tz_world -来自Eric Muller的原始shapefile数据 whereonearth-timezone - GeoJSON版本与WOEDB数据合并
时区地理定位离线实现
使用时区边界生成器数据的实现
node-geo-tz - JavaScript library (Node.js only) timespace - JavaScript library tz-lookup-oss - JavaScript library GeoTimeZone - .NET library Geo-Timezone - PHP library timezonefinder - Python library ZoneDetect - C library Timeshape - Java library TimeZoneMap - Java and Android library lutz - R library go-tz - Go library Timezone lookup - Go library docker-timezone-lookup - docker container wrapping node-geo-tz tzf - Go library tzfpy - Python port of tzf library tzf-rs - Rust port of tzf library
使用较旧的tz_world数据的实现
latlong - Go库(也可以阅读这篇文章)。 TimeZoneMapper - Java库 tzwhere - JavaScript/节点库 pytzwhere - Python库 timezone_finder - Ruby库 LatLongToTimeZone - Java和Swift库 现在几点了?-描述PHP和MongoDB的博客文章 rundel/timezone - R库
调用其中一个web服务的库
timezone -调用GeoNames的Ruby宝石 AskGeo有自己的库,用于从Java或。net进行调用 GeoNames拥有几乎所有东西的客户端库
自托管web服务
geo2tz -基于时区查找,可通过Docker image获得
其他的想法
找到最近有R-Tree的城市 用MySQL找到最近的城市
如果您知道其他名单,请更新此名单
此外,请注意,最近的城市方法可能不会产生“正确”的结果,只是一个近似值。
转换到Windows区域
列出的大多数方法都将返回IANA时区id。如果您需要转换为Windows时区,以便与。net中的TimeZoneInfo类一起使用,请使用TimeZoneConverter库。
不要使用zone.tab
tz数据库包含一个名为zone.tab的文件。该文件主要用于显示时区列表,供用户从中选择。它包括每个时区参考点的纬度和经度坐标。这允许创建一个突出显示这些点的地图。例如,查看moment-timezone主页上显示的交互式地图。
虽然使用这些数据从纬度和经度坐标解析时区可能很诱人,但请考虑这些是点,而不是边界。最好的办法是确定最近的点,但在许多情况下,这并不是正确的点。
考虑下面的例子:
这两个方格表示不同的时区,其中每个方格中的黑点是参考位置,例如在zone.tab中可以找到的位置。蓝点表示我们试图为其寻找时区的位置。显然,这个位置位于左侧的橙色区域内,但如果我们只看距离参考点最近的距离,它将解析为右侧的绿色区域。
尝试以下代码使用谷歌时区API从Java与当前NTP时间客户端和正确的UTC_Datetime_from_timestamp转换:
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;
}
private String get_UTC_Datetime_from_timestamp(long timeStamp){
try{
Calendar cal = Calendar.getInstance();
TimeZone tz = cal.getTimeZone();
int tzt = tz.getOffset(System.currentTimeMillis());
timeStamp -= tzt;
// DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss",Locale.getDefault());
DateFormat sdf = new SimpleDateFormat();
Date netDate = (new Date(timeStamp));
return sdf.format(netDate);
}
catch(Exception ex){
return "";
}
}
class NTP_UTC_Time
{
private static final String TAG = "SntpClient";
private static final int RECEIVE_TIME_OFFSET = 32;
private static final int TRANSMIT_TIME_OFFSET = 40;
private static final int NTP_PACKET_SIZE = 48;
private static final int NTP_PORT = 123;
private static final int NTP_MODE_CLIENT = 3;
private static final int NTP_VERSION = 3;
// Number of seconds between Jan 1, 1900 and Jan 1, 1970
// 70 years plus 17 leap days
private static final long OFFSET_1900_TO_1970 = ((365L * 70L) + 17L) * 24L * 60L * 60L;
private long mNtpTime;
public boolean requestTime(String host, int timeout) {
try {
DatagramSocket socket = new DatagramSocket();
socket.setSoTimeout(timeout);
InetAddress address = InetAddress.getByName(host);
byte[] buffer = new byte[NTP_PACKET_SIZE];
DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, NTP_PORT);
buffer[0] = NTP_MODE_CLIENT | (NTP_VERSION << 3);
writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET);
socket.send(request);
// read the response
DatagramPacket response = new DatagramPacket(buffer, buffer.length);
socket.receive(response);
socket.close();
mNtpTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET);
} catch (Exception e) {
// if (Config.LOGD) Log.d(TAG, "request time failed: " + e);
return false;
}
return true;
}
public long getNtpTime() {
return mNtpTime;
}
/**
* Reads an unsigned 32 bit big endian number from the given offset in the buffer.
*/
private long read32(byte[] buffer, int offset) {
byte b0 = buffer[offset];
byte b1 = buffer[offset+1];
byte b2 = buffer[offset+2];
byte b3 = buffer[offset+3];
// convert signed bytes to unsigned values
int i0 = ((b0 & 0x80) == 0x80 ? (b0 & 0x7F) + 0x80 : b0);
int i1 = ((b1 & 0x80) == 0x80 ? (b1 & 0x7F) + 0x80 : b1);
int i2 = ((b2 & 0x80) == 0x80 ? (b2 & 0x7F) + 0x80 : b2);
int i3 = ((b3 & 0x80) == 0x80 ? (b3 & 0x7F) + 0x80 : b3);
return ((long)i0 << 24) + ((long)i1 << 16) + ((long)i2 << 8) + (long)i3;
}
/**
* Reads the NTP time stamp at the given offset in the buffer and returns
* it as a system time (milliseconds since January 1, 1970).
*/
private long readTimeStamp(byte[] buffer, int offset) {
long seconds = read32(buffer, offset);
long fraction = read32(buffer, offset + 4);
return ((seconds - OFFSET_1900_TO_1970) * 1000) + ((fraction * 1000L) / 0x100000000L);
}
/**
* Writes 0 as NTP starttime stamp in the buffer. --> Then NTP returns Time OFFSET since 1900
*/
private void writeTimeStamp(byte[] buffer, int offset) {
int ofs = offset++;
for (int i=ofs;i<(ofs+8);i++)
buffer[i] = (byte)(0);
}
}
String get_time_zone_time(GeoPoint gp){
String erg = "";
String raw_offset = "";
String dst_offset = "";
double Longitude = gp.getLongitudeE6()/1E6;
double Latitude = gp.getLatitudeE6()/1E6;
long tsLong = 0; // System.currentTimeMillis()/1000;
NTP_UTC_Time client = new NTP_UTC_Time();
if (client.requestTime("pool.ntp.org", 2000)) {
tsLong = client.getNtpTime();
}
if (tsLong != 0)
{
tsLong = tsLong / 1000;
// https://maps.googleapis.com/maps/api/timezone/xml?location=39.6034810,-119.6822510×tamp=1331161200&sensor=false
String request = "https://maps.googleapis.com/maps/api/timezone/xml?location="+Latitude+","+ Longitude+ "×tamp="+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;
erg = get_UTC_Datetime_from_timestamp(tsLong);
}
return erg;
}
并将其用于:
GeoPoint gp = new GeoPoint(39.6034810,-119.6822510);
String Current_TimeZone_Time = get_time_zone_time(gp);
好的,这是没有正确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×tamp=1331161200&sensor=false
String request = "https://maps.googleapis.com/maps/api/timezone/xml?location="+Latitude+","+ Longitude+ "×tamp="+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);
通过使用纬度和经度得到当前位置下面的时区代码为我工作
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×tamp=1331161200";
// timezoneurl = timezoneurl+"location="+lat+","+lng+"×tamp=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();
}