如何从使用经纬度坐标的位置获得时区?

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

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

334536 次浏览

时区位置Web服务

原始时区边界数据

  • 时区边界构建器 -从OpenStreetMaps地图数据构建时区形状文件。包括海岸线附近的领海。

以下项目以前是时区边界数据的来源,但不再积极维护。

时区地理定位离线实现

使用时区边界生成器数据的实现

使用较旧的tz_world数据的实现

调用其中一个web服务的库

  • 时区 - Ruby宝石调用GeoNames
  • AskGeo有自己的库,用于从Java或.Net调用
  • GeoNames拥有几乎所有东西的客户端库

自托管web服务

其他的想法

如果您知道其他名单,请更新此名单

此外,请注意,最近的城市方法可能不会产生“正确的”;结果,只是一个近似。

转换到Windows区域

列出的大多数方法都将返回IANA时区id。如果你需要转换为Windows时区以便与。net中的TimeZoneInfo类一起使用,请使用TimeZoneConverter库。

不要使用zone.tab

tz数据库包含一个名为zone.tab的文件。该文件主要用于显示时区列表,供用户从中选择。它包括每个时区参考点的纬度和经度坐标。这允许创建一个突出显示这些点的地图。例如,请参阅moment-timezone主页中显示的交互式地图。

虽然使用这些数据从纬度和经度坐标解析时区可能很诱人,但请考虑这些是点,而不是边界。最好的方法是确定最亲密的点,在许多情况下,这不是正确的点。

考虑下面的例子:

Time Zone Example Art

这两个方格表示不同的时区,其中每个方格中的黑点是参考位置,例如在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&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;






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

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

如果你不想使用web服务,你可以像这样从浏览器中检索信息:

var d = new Date();
var usertime = d.toLocaleString();


//some browsers / OSs provide the timezone name in their local string
var tzsregex = /\b(ACDT|ACST|ACT|ADT|AEDT|AEST|AFT|AKDT|AKST|AMST|AMT|ART|AST|AWDT|AWST|AZOST|AZT|BDT|BIOT|BIT|BOT|BRT|BST|BTT|CAT|CCT|CDT|CEDT|CEST|CET|CHADT|CHAST|CIST|CKT|CLST|CLT|COST|COT|CST|CT|CVT|CXT|CHST|DFT|EAST|EAT|ECT|EDT|EEDT|EEST|EET|EST|FJT|FKST|FKT|GALT|GET|GFT|GILT|GIT|GMT|GST|GYT|HADT|HAEC|HAST|HKT|HMT|HST|ICT|IDT|IRKT|IRST|IST|JST|KRAT|KST|LHST|LINT|MART|MAGT|MDT|MET|MEST|MIT|MSD|MSK|MST|MUT|MYT|NDT|NFT|NPT|NST|NT|NZDT|NZST|OMST|PDT|PETT|PHOT|PKT|PST|RET|SAMT|SAST|SBT|SCT|SGT|SLT|SST|TAHT|THA|UYST|UYT|VET|VLAT|WAT|WEDT|WEST|WET|WST|YAKT|YEKT)\b/gi;


//in other browsers the timezone needs to be estimated based on the offset
var timezonenames = {"UTC+0":"GMT","UTC+1":"CET","UTC+2":"EET","UTC+3":"EEDT","UTC+3.5":"IRST","UTC+4":"MSD","UTC+4.5":"AFT","UTC+5":"PKT","UTC+5.5":"IST","UTC+6":"BST","UTC+6.5":"MST","UTC+7":"THA","UTC+8":"AWST","UTC+9":"AWDT","UTC+9.5":"ACST","UTC+10":"AEST","UTC+10.5":"ACDT","UTC+11":"AEDT","UTC+11.5":"NFT","UTC+12":"NZST","UTC-1":"AZOST","UTC-2":"GST","UTC-3":"BRT","UTC-3.5":"NST","UTC-4":"CLT","UTC-4.5":"VET","UTC-5":"EST","UTC-6":"CST","UTC-7":"MST","UTC-8":"PST","UTC-9":"AKST","UTC-9.5":"MIT","UTC-10":"HST","UTC-11":"SST","UTC-12":"BIT"};


var timezone = usertime.match(tzsregex);
if (timezone) {
timezone = timezone[timezone.length-1];
} else {
var offset = -1*d.getTimezoneOffset()/60;
offset = "UTC" + (offset >= 0 ? "+" + offset : offset);
timezone = timezonenames[offset];
}


//there are 3 variables can use to see the timezone
// usertime - full date
// offset - UTC offset time
// timezone - country


console.log('Full Date: ' + usertime);
console.log('UTC Offset: ' + offset);
console.log('Country Code Timezone: ' + timezone);

在我目前的情况下,它是打印:

完整的日期:“27”/“01”/“2014”“16”:“53”:“37” UTC抵消: UTC-3 国家代码时区: BRT

希望对大家有所帮助。

node.js的这个解决方案怎么样 https://github.com/mattbornski/tzwhere < / p >

及其Python对等体: https://github.com/pegler/pytzwhere < / p >

通过使用纬度和经度得到当前位置下面的时区代码为我工作

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

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

下面是使用JSON数据的一个很好的实现: https://github.com/agap/llttz < / p >
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());
}
}

我们在传送刚刚启动了开放我们的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"
}

在本例中,我使用。/金桥进行JSON解析。

从古比鱼:

import geocoders
g = geocoders.GoogleV3()
place, (lat, lng) = g.geocode('Fairbanks')
print place, (lat, lng)
Fairbanks, AK, USA (64.8377778, -147.7163889)
timezone = g.timezone((lat, lng))
print timezone.dst

DstTzInfo的绑定方法America/Anchorage.dst

美国/安克雷奇' LMT-1日,14:00:00标准时间

你可以使用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
}
  1. 网上有几个资源,有时区的geojson数据(这里是一个这里是另一个)

  2. 使用几何库从geojson坐标创建多边形对象( shaely [python], GEOS [c++], JTS [java], NTS [.net])。

  3. 将您的lat/lng转换为一个点对象(但是您的库表示它),并检查它是否与时区多边形相交。

    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
    

认识到这是一个比大多数人想象的更复杂的问题,这确实很重要。在实践中,我们中的许多人也愿意接受一套适用于“尽可能多的情况”的代码,其中至少可以确定致命问题并将其整体最小化。所以我把所有这些和OP的精神放在心上。最后,对于那些试图将GPS转换为时区,最终目标是拥有一个位置敏感的时间对象的人(更重要的是帮助提高本wiki中时间对象的平均实现质量),这里是我在Python中生成的内容(请随意编辑):

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)

下面是如何使用谷歌的脚本编辑器来获取gsheet中的timezoneName和timeZoneId。

 ></a></p>


<p>步骤1。<a href=获取API密钥用于谷歌的时区API

步骤2。创建一个新的gsheet。在“工具”菜单下单击“脚本编辑器”。添加如下代码:

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"];
}

步骤3。保存并发布你的getTimezone()函数,并如上图所示使用它。

  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>

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

  1. 通过地理定位获取lat/lng
  2. 通过传递获取时区 进入时区API
    • 此处使用勒克桑进行时区转换。
    • 李< / ul > < / >

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

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

披露:我是下面描述的docker-image的作者

我将https://github.com/evansiroky/node-geo-tz包装在一个非常简单的docker-container中

https://hub.docker.com/repository/docker/tobias74/timezone-lookup

您可以启动docker容器

docker run -p 80:3000 tobias74/timezone-lookup:latest

这将公开端口3000上的本地主机上的查找服务。然后可以执行时区查找

curl "localhost:3000/timezone?latitude=12&longitude=34"

我写了一个包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样本:

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