给定一个位置的经度和纬度,如何知道该位置的有效时区?
在大多数情况下,我们正在寻找IANA/Olson时区id,尽管有些服务可能只返回UTC偏移量或其他一些时区标识符。详细信息请阅读时区标签信息。
给定一个位置的经度和纬度,如何知道该位置的有效时区?
在大多数情况下,我们正在寻找IANA/Olson时区id,尽管有些服务可能只返回UTC偏移量或其他一些时区标识符。详细信息请阅读时区标签信息。
时区位置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);
如果您想使用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
和它的Python对等体: https://github.com/pegler/pytzwhere
通过使用纬度和经度得到当前位置下面的时区代码为我工作
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();
}
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解析。
从古比鱼:
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的dst
美国/主播LMT-1天,STD 1400: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
}
There are several sources online that have geojson data for timezones (here's one, here's another) Use a geometry library to create polygon objects from the geojson coordinates (shapely [python], GEOS [c++], JTS [java], NTS [.net]). Convert your lat/lng to a point object (however your library represents that) and check if it intersects the timezone polygon. 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
It's indeed important to recognize that this a more complicated problem than most would suspect. In practice many of us are also willing to accept a working set of code that works for "as many cases as possible", where at least its fatal issues can be identified and minimized collectively. So I post this with all of that and the spirit of the OP in mind. Finally, for practical value to others who are trying to convert GPS to timezone with the end goal of having a location-sensitive time object (and more importantly to help advance the quality of average implementations with time objects that follow from this wiki) here is what I generated in Python (please feel free to edit):
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。
步骤1。获取谷歌的时区API的API键
步骤2。创建一个新的gsheet。在“工具”菜单下单击“脚本编辑器”。添加如下代码:
function getTimezone(lat, long) {
var apiKey = 'INSERTAPIKEYHERE'
var url = 'https://maps.googleapis.com/maps/api/timezone/json?location=' + lat + ',' + long + '×tamp=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从邮政编码获取时区的人来说,这里有一个方法。
通过地理定位获取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);
披露:我是下面描述的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 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));
}