2015-11-10 111 views
1

我正在編寫一個應用程序,該應用程序應根據您提供的座標(經緯度爲長)給出本地時間。根據座標獲取當地時間

我只知道有2種方法來做到這一點:

1:獲得區名稱,然後找到其本地時間。 第二:使用Google API並將時間作爲偏移量,UTC不是本地時間。

我決定使用第一種方法,因爲看起來更容易,所以我決定使用GeoTimeZone來獲取時區...問題是,我不知道如何獲得該時區的本地時間..這是我寫的獲取時區名稱的代碼。

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

變量lat & lon是當然的座標。

謝謝!

編輯:我的問題是如何獲得該時區的LocalTime?

+0

'TimeZoneLookup.GetTimeZone(lat,lon).Result;'這是什麼?什麼是'TimeZoneLookup'?什麼'GetTimeZone'返回? 「結果」的價值是什麼? – sab669

+0

@ sab669你有這方面的一些信息:https://github.com/mj1856/GeoTimeZone – ctabuyo

+1

請參閱codeproject:http://www.codeproject.com/Questions/758354/get-timezone-and-location-name-使用緯度和 – jdweng

回答

4

您可以使用谷歌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()); 
} 
+0

這是一個非常好的主意。請檢查我對其他答案的評論,我已收到您的答案。無論如何解決這個問題?我寧願使用另一種方法,因爲這有點乏味。但無論如何,如果沒有辦法,我會用你的方法。 – ctabuyo

+0

@ctabuyo我認爲沒有別的辦法。爲了獲得當地時間,我們需要知道當前位置名稱是在框架和環境之間標準化的。這就是爲什麼使用某些第三方服務或某些預定義數據庫的位置 - >時區數據可以使用。其實我不知道你的情況,建議你一些更有用的方法。但我相信這是處理這種業務邏輯的好方法。因爲Google服務是高可用性服務。 –

+0

夠公平的,謝謝! – ctabuyo

0

您可以用下面的代碼轉換當前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(); 
+0

這是我到目前爲止嘗試過的,問題是,我使用的制服得到TimeZone名稱,給我這樣的名字:「America/Chicago」,那麼FindSystemTimeZoneById會給出錯誤,因爲它找不到它。 – ctabuyo

+0

@ctabuyo是的,您只能在Windows時區使用此方法,但不能與IANA時區不同。 –

1

最後這是我的固定它,我需要使用TimeZoneDb它將IANA時區變爲Microsoft格式,因此這是執行此操作的代碼:

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

T對任何一個幫助過的人來說,這兩個解決方案對我幫助很大,也許沒有他們我無法實現它。

非常感謝!

0

這裏我的解決方案基於混合解決方案。需要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); 

}