【问题标题】:How to get a time zone from a location using latitude and longitude coordinates?如何使用纬度和经度坐标从某个位置获取时区?
【发布时间】:2019-09-08 21:34:39
【问题描述】:

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

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

【问题讨论】:

  • 我注意到的一件事是在确定时区时缺少任何 UTC 时间戳要求。例如,伦敦的长/纬度不足以确定时区是 GMT 或 BST(英国夏令时/夏令时)的天气。所以肯定要确定正确的时区,您需要 lat、long 和 UTC 时间戳。
  • @MichaelWaterfall - 要确定您是在 GMT (UTC+0000) 还是 BST (UTC+0100) - 是的,您是绝对正确的。但这些是时区偏移量,而不是时区标识符。两者都包含在 IANA 时区数据库的同一 "Europe/London" 时区标识符中。
  • 好吧,一旦使用给定的时区标识符渲染时间,就会添加夏令时偏移量(如果需要)?
  • 它仍然可能需要 UTC 时间戳。例如,俄罗斯在过去 6 年中 4 次更改时区边界。 en.wikipedia.org/wiki/Time_in_Russia
  • @thur - 就边界本身而言,随着边界争端的开始或结束,每年都有一些历史差异。但是,当发生像 Arnial 所描述的那样的转变时,tzdb 会为受影响的区域创建一个新的时区,因此该区域的所有时间都会被计算在内 - 包括历史差异。我们称之为“区域分割”。一个很好的俄罗斯例子是Europe/Astrakhan,它与 tzdb 2016b 的Europe/Volgograd 分开。

标签: geolocation timezone latitude-longitude


【解决方案1】:

时区定位网络服务

原始时区边界数据

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

时区地理位置离线实现

使用时区边界构建器数据的实现

使用旧 tz_world 数据的实现

调用其中一种网络服务的库

  • timezone - 调用 GeoNames 的 Ruby gem
  • AskGeo 有自己的库,用于从 Java 或 .Net 调用
  • GeoNames 拥有几乎所有内容的客户端库

自托管网络服务

其他想法

如果您知道其他人,请更新此列表

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

转换为 Windows 区域

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

不要使用 zone.tab

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

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

考虑以下示例:

                    

两个方块代表不同的时区,其中每个方块中的黑点是参考位置,例如可以在 zone.tab 中找到的位置。蓝点代表我们试图为其查找时区的位置。显然,这个位置在左侧的橙色区域内,但如果我们只看离参考点最近的距离,它将解析为右侧的绿色区域。

【讨论】:

  • GeoNames 实际上非常适合我的需要。谢谢!
  • @Matt 但是,据我了解,目前没有离线数据库可以根据位置坐标提供时区信息和与 UTC 的偏移量?
  • @MattJohnson 我如何使用地名客户端库
  • 这些新的 Google API 费率是敲诈勒索的。截至 7 月 18 日,200 个请求为 1 美元。这是 10 倍的增长。
  • @KanagaveluSugumar - 每个库的语言都包含在列表中。当前对 Java 的最高推荐是 TimeShape
【解决方案2】:

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

还有它的 Python 对应物: https://github.com/pegler/pytzwhere

【讨论】:

  • 我将这些添加到上面的社区 wiki 答案中。谢谢!
【解决方案3】:

我们Teleport 刚刚开始opening up our API's,其中一个用例还公开了坐标的 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 解析的示例。

【讨论】:

  • 感谢分享。它是在做最近城市的方法,还是在使用多边形内的方法? (参见我上面两个正方形的图表。)
  • 嗨 Joonathan,这是我第一次在 json 中看到像你这样的对象或数组名称,例如这个:“location:nearest-cities”:[以后如何才能得到结果? $city = $data->_embedded->location:nearest->cities[0]->_links->location:nearest->cities->name 这是不允许的
【解决方案4】:

下面介绍了如何使用 Google 的脚本编辑器在 gsheet 中获取 timezoneName 和 timeZoneId。

第 1 步。Get an API key 用于 Google 的时区 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() 函数并使用它,如上图所示。

【讨论】:

    【解决方案5】:

    您可以使用geolocator.js 轻松获取时区等等...

    它使用需要密钥的 Google API。所以,首先你配置地理定位器:

    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
    }
    

    定位然后获取 TimeZone 等等

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

    下面的示例将首先尝试 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
    }
    

    【讨论】:

      【解决方案6】:

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

      【讨论】:

      • 你能从链接中添加一些内容吗?
      【解决方案7】:

      认识到这是一个比大多数人想象的更复杂的问题确实很重要。在实践中,我们中的许多人也愿意接受一组适用于“尽可能多的情况”的工作代码,其中至少可以识别和最小化其致命问题。因此,我在发布此内容时考虑了所有这些以及 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)
      

      【讨论】:

      • 谢谢,但这看起来像是一些使用 pytzwhere 的代码,它已经列在主要社区 wiki 答案中。如果您打算提供如何将 pytzwhere 与 pytz 结合使用的示例,您可能希望将其作为 PR 提交给 pytzwhere 项目本身。在这里,我们只是在寻找经纬度到 tz 的解决方案 - 其中 pytzwhere 就是其中之一。
      【解决方案8】:
      1. 有几个在线来源提供时区的 geojson 数据(here's onehere's 另一个)

      2. 使用几何库从 geojson 坐标创建多边形对象(shapely [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
        

      【讨论】:

        【解决方案9】:

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

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

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

        你可以使用 docker-container 来启动

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

        这会在 localhost 的 3000 端口上公开查找服务。然后您可以通过

        进行时区查找
        curl "localhost:3000/timezone?latitude=12&longitude=34"
        

        【讨论】:

          【解决方案10】:

          尝试此代码以使用 Java 中的 Google Time Zone API 与当前 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 客户端,这可能是个好主意 - 但不一定是必需的。能瘦一点吗?
          【解决方案11】:

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

          【讨论】:

            【解决方案12】:

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

            【讨论】:

              【解决方案13】:

              来自孔雀鱼:

              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
              

              绑定方法America/Anchorage.dstDstTzInfo

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

              【讨论】:

              • 我认为 Guppy 是一个错字。你的意思是Geopy 还是别的什么?
              【解决方案14】:

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

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

              【讨论】:

              • 您在呼叫哪个服务?您真的想与我们分享您的密钥吗??
              【解决方案15】:

              对于我们这些使用 Javascript 并希望通过 Google API 从邮政编码获取时区的人,这是一种方法。

              1. 通过地理位置获取 lat/lng
              2. 获取时区 进入timezone 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);
              

              【讨论】:

                【解决方案16】:

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

                希望对您有所帮助。

                【讨论】:

                • 虽然我感谢您为此付出了一些努力,但请注意:1) 时区不是固定偏移量 2) 时区缩写不是标准化或唯一标识符 3) 这已经完成了,还有更多准确地说,是jsTimeZoneDetect。 4)您的答案与问题不符。问题是如何从纬度和经度坐标确定时区。
                【解决方案17】:

                  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>

                【讨论】:

                • 伙计们,您必须将代码复制并粘贴到新的浏览器中,因为代码 sn-p 不允许我们提示用户的位置
                • 希望大家欣赏
                • 输入 lat 和 lng 后,按位置,GMT 然后激活时钟
                • 我真的不认为您打算与我们共享您的 API 密钥到 opencagedata,是吗?您可以简单地描述这个 API,而不是转储代码。
                • 好吧,有些人只需要看一个api的回调函数示例就可以更好地理解
                猜你喜欢
                • 2021-12-09
                相关资源
                最近更新 更多