【问题标题】:Get local time based on coordinates根据坐标获取当地时间
【发布时间】:2015-11-10 21:02:55
【问题描述】:

我正在编写一个应用程序,该应用程序应根据您提供的坐标(纬度和经度)提供本地时间。

我只知道两种方法可以做到这一点:

1st:获取时区名称,然后找到它的本地时间。 第二:使用 Google API 接收时间作为偏移量,UTC 不是本地时间。

我决定使用第一种方法,因为它看起来更容易,所以我决定使用 GeoTimeZone 来获取时区......问题是我不知道如何获取那个 TimeZone 的当地时间......这是我为获取 TimeZone 名称而编写的代码。

string tz = TimeZoneLookup.GetTimeZone(lat, lon).Result;

变量lat & lon 当然是坐标。

谢谢!

编辑:我的问题是如何获取该时区的 LocalTime?

【问题讨论】:

标签: c# datetime


【解决方案1】:

这是我的解决方案。它可以离线工作(因此无需调用 api)。它速度很快,而且这些包在 Nuget 上被广泛使用和提供。

string tzIana = TimeZoneLookup.GetTimeZone(lat, lng).Result;
TimeZoneInfo tzInfo = TZConvert.GetTimeZoneInfo(tzIana);
DateTimeOffset convertedTime = TimeZoneInfo.ConvertTime(DateTimeOffset.UtcNow, tzInfo);

【讨论】:

  • 这是什么 nuget 包?
  • NuGet 包似乎是 GeoTimeZone 和 TimeZoneConvertor。
  • 他们确实是GeoTimeZoneTimeZoneConverter。我更新了代码以简化并使其适用于所有支持的平台,并返回完整的DateTimeOffset
  • 这绝对是一个很好的解决方案。我想知道当世界各地的时区随着时间的推移而改变时会发生什么?例如,一个国家可能决定放弃夏令时并全年保持夏令时。这些包会使用 Windows 更新中的信息,还是需要更新这些包?
  • 阅读文档后,如果时区数据发生变化,似乎需要更新包。在这种情况下,仅仅更新 Windows 是不够的。
【解决方案2】:

您可以使用 Google api 来识别当前时区。
.Net Fiddle example:

public class Program
{
    public static DateTime GetLocalDateTime(double latitude, double longitude, DateTime utcDate)
    {
        var client = new RestClient("https://maps.googleapis.com");
        var request = new RestRequest("maps/api/timezone/json", Method.GET);
        request.AddParameter("location", latitude + "," + longitude);
        request.AddParameter("timestamp", utcDate.ToTimestamp());
        request.AddParameter("sensor", "false");
        var response = client.Execute<GoogleTimeZone>(request);

        return utcDate.AddSeconds(response.Data.rawOffset + response.Data.dstOffset);
    }

    public static void Main()
    {
        var myDateTime = GetLocalDateTime(33.8323, -117.8803, DateTime.UtcNow);
        Console.WriteLine(myDateTime.ToString());
    }
}

public class GoogleTimeZone 
{
    public double dstOffset { get; set; }
    public double rawOffset { get; set; }
    public string status { get; set; }
    public string timeZoneId { get; set; }
    public string timeZoneName { get; set; }
}

public static class ExtensionMethods 
{
    public static double ToTimestamp(this DateTime date)
    {
        DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0);
        TimeSpan diff = date.ToUniversalTime() - origin;
        return Math.Floor(diff.TotalSeconds);
    }
}

然后您可以轻松地使用您的 GetLocalDateTime(double latitude, double longitude, DateTime utcDate) 方法,如上例所示:

public static void Main()
{
    var myDateTime = GetLocalDateTime(33.8323, -117.8803, DateTime.UtcNow);
    Console.WriteLine(myDateTime.ToString());
}

【讨论】:

  • 这是一个非常好的主意。请检查我对低于您的其他答案的评论。有没有办法解决这个问题?我宁愿使用另一种方法而不是这种方法,因为这有点乏味。但无论如何,如果没有办法,我会用你的方法。
  • @ctabuyo 我认为没有其他办法。要获取本地时间,我们需要知道框架和环境之间标准化的当前位置名称。这就是为什么使用一些 3rd 方服务或一些带有位置-> 时区数据的预定义数据库看起来不错的原因。实际上,我不知道您的情况是否可以建议您采取更有用的方法。但我相信这是处理这种业务逻辑的好方法。因为 Google 服务是高可用性服务。
  • 据我所知,所有 Google API 都有每 24 小时的限制——尤其是请求数量。如果您计划在生产中使用此代码,则应检查这些限制以避免意外中断。
  • 只是补充一点,此代码不再按原样工作。 Google Map API 现在需要一个帐户,您需要将 API 密钥作为参数发送
【解决方案3】:

最后这就是我修复它的方法,我需要使用将 IANA 时区转换为 Microsoft 格式的 TimeZoneDb 涂装,所以这是执行此操作的代码:

string tz1 = TimeZoneLookup.GetTimeZone(lat, lon).Result;

                var timeZoneDbUseCases = new TimeZoneDbUseCases();
                var allTimeZones = timeZoneDbUseCases.GetAllTimeZones();
                var timeZone = timeZoneDbUseCases.GetTimeZoneWithIanaId(tz1);

                var timeZone1 = TimeZoneInfo.FindSystemTimeZoneById(timeZone.MicrosoftId);
                var localTime = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, timeZone1);

感谢任何提供帮助的人,这两种解决方案都对我帮助很大,如果没有它们,我可能无法实现。

非常感谢!!

【讨论】:

  • TimeZoneDb 非常非常慢。而且包有一些依赖问题。
【解决方案4】:

您可以使用以下代码将当前 UTC 时间转换为本地时间:

var tz = "Eastern Standard Time"; // local time zone
var timeZone = TimeZoneInfo.FindSystemTimeZoneById(tz);
var localTime = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, timeZone);

//Console.WriteLine(localTime.ToString("G"));
//Console.ReadLine();

【讨论】:

  • 这是我迄今为止尝试过的,问题是我用来获取 TimeZone 名称的制服给了我这样的名字:“America/Chicago”,所以 FindSystemTimeZoneById 给出一个错误,因为它找不到它。
  • @ctabuyo 是的,您只能将此方法用于 Windows 时区,但不能用于不同的 IANA 时区。
【解决方案5】:

这里是我的基于混合解决方案的解决方案。需要 RestSharp 和 NodaTime(都来自 nuget)

    private static string WindowsToIana(string windowsZoneId)
    {
        if (windowsZoneId.Equals("UTC", StringComparison.Ordinal))
            return "Etc/UTC";

        var tzdbSource = NodaTime.TimeZones.TzdbDateTimeZoneSource.Default;
        var tzi = TimeZoneInfo.FindSystemTimeZoneById(windowsZoneId);
        if (tzi == null) return null;
        var tzid = tzdbSource.MapTimeZoneId(tzi);
        if (tzid == null) return null;
        return tzdbSource.CanonicalIdMap[tzid];
    }

    private static string IanaToWindows(string ianaZoneId)
    {
        var utcZones = new[] { "Etc/UTC", "Etc/UCT", "Etc/GMT" };
        if (utcZones.Contains(ianaZoneId, StringComparer.Ordinal))
            return "UTC";

        var tzdbSource = NodaTime.TimeZones.TzdbDateTimeZoneSource.Default;

        // resolve any link, since the CLDR doesn't necessarily use canonical IDs
        var links = tzdbSource.CanonicalIdMap
            .Where(x => x.Value.Equals(ianaZoneId, StringComparison.Ordinal))
            .Select(x => x.Key);

        // resolve canonical zones, and include original zone as well
        var possibleZones = tzdbSource.CanonicalIdMap.ContainsKey(ianaZoneId)
            ? links.Concat(new[] { tzdbSource.CanonicalIdMap[ianaZoneId], ianaZoneId })
            : links;

        // map the windows zone
        var mappings = tzdbSource.WindowsMapping.MapZones;
        var item = mappings.FirstOrDefault(x => x.TzdbIds.Any(possibleZones.Contains));
        if (item == null) return null;
        return item.WindowsId;
    }

    private static string GetIanaTimeZone(double latitude, double longitude, DateTime date)
    {
        RestClient client;
        string location;
        RestRequest request;
        RestResponse response;
        TimeSpan time_since_midnight_1970;
        double time_stamp;
        string time_zone = "";

        try
        {
            const string GOOGLE_API = "https://maps.googleapis.com";
            const string GOOGLE_TIMEZONE_REQUEST = "maps/api/timezone/xml";


            client = new RestClient(GOOGLE_API);
            request = new RestRequest(GOOGLE_TIMEZONE_REQUEST,
                                        Method.GET);
            location = String.Format("{0},{1}",
                                       latitude.ToString(CultureInfo.InvariantCulture),
                                       longitude.ToString(CultureInfo.InvariantCulture));

            DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0);
            time_since_midnight_1970 = date - origin;
            time_stamp = Math.Floor(time_since_midnight_1970.TotalSeconds);

            request.AddParameter("location", location);
            request.AddParameter("timestamp", time_stamp);
            request.AddParameter("sensor", "false");
            //request.AddParameter("key", yourgooglekey);

            response = (RestResponse)client.Execute(request);
            if (response.StatusDescription.Equals("OK"))
            {
                XmlNode node;
                XmlDocument xml_document = new XmlDocument();

                xml_document.LoadXml(response.Content);
                node = xml_document.SelectSingleNode(
                            "/TimeZoneResponse/time_zone_id");
                if (node != null)
                {
                    time_zone = node.InnerText;
                }
                else
                {

                }
            }
            else
            {

            }
        }
        catch (Exception ex)
        {

        }

        return time_zone;
    }

    public static DateTime? GetDateTimeFromCoordinates(DateTime? utc, double? latitude, double? longitude)
    {
        if (utc == null || latitude == null || longitude == null)
            return null;

        try
        {
            string iana_timezone = GetIanaTimeZone((double)latitude, (double)longitude, (DateTime)utc);
            if (string.IsNullOrWhiteSpace(iana_timezone))
                return null;

            string time_zone = IanaToWindows(iana_timezone);
            TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById(time_zone);
            DateTime date = TimeZoneInfo.ConvertTimeFromUtc((DateTime)utc, tz);
            return date;
        }
        catch (Exception ex)
        {

            return null;
        }

    }
}

static void Main(string[] args)
{
    double latitude = -11.2026920;
    double longitude = 17.8738870;
    DateTime uct = DateTime.UtcNow;

   DateTime? ret = GetDateTimeFromCoordinates(utc,latitude,longitude);

}

【讨论】:

    【解决方案6】:

    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 不允许我们提示
    • 希望大家欣赏
    猜你喜欢
    • 2011-05-21
    • 2019-01-29
    • 1970-01-01
    • 2015-05-23
    • 1970-01-01
    • 1970-01-01
    • 2018-05-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多