Get local time based on coordinates
Asked Answered
P

6

12

I am programming an application that should give the local time based on the coordinates (lat&long) that you give it.

I only know of 2 methods to do that:

1st: Get the TimeZone Name, and then find its local time. 2nd: Use the Google API and receive the time as an offset and UTC not Local.

I decided to use the 1st method because seemed easier, so I decided to use the GeoTimeZone to get the Time Zone... Problem is that then I don´t know how to get the local time on that TimeZone... Here´s the code I wrote to get the TimeZone name.

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

variables lat & lon are of course the coordinates.

Thank you!

Edit: My question is how can I get the LocalTime on that TimeZone?

Persuader answered 10/11, 2015 at 21:2 Comment(4)
TimeZoneLookup.GetTimeZone(lat, lon).Result; what is any of that? What is TimeZoneLookup? What does GetTimeZone return? What is the value of Result?Grover
@Grover you have some information about it here: github.com/mj1856/GeoTimeZonePersuader
See codeproject : codeproject.com/Questions/758354/…Pipsissewa
See #3537651Khelat
K
8

You can do it using Google api for identifying current timezone.
.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);
    }
}

And then you can easily use your GetLocalDateTime(double latitude, double longitude, DateTime utcDate) method as it was shown in the example above:

public static void Main()
{
    var myDateTime = GetLocalDateTime(33.8323, -117.8803, DateTime.UtcNow);
    Console.WriteLine(myDateTime.ToString());
}
Kike answered 10/11, 2015 at 22:55 Comment(4)
it is a very good idea. Please check what I comment on the other answer that I got below yours. Is there anyway to fix that? I´d rather using the other method over than this one because this is a little tedious. But anyway if there´s no way, I will use your method.Persuader
@ctabuyo I think there is no other way.. To get local time we need to know the current location name that is standardised between frameworks and environments. That's why it's look ok to use some 3rd party service or some predefined database with locations->timezones data. Actually I don't know your case to suggest you something more useful approach. But I believe it's nice way to handle this business logic. as Google services is high availability service.Kike
As far as I know, all Google APIs have limits per 24 hours - especially number of requests. You should check those limits to avoid unexpected interruptions if you plan to use this code in production.Brantbrantford
Just to add that this code doesn't work as-is anymore. Google Map API now requires an account and you need to send your API key as a parameterTamishatamma
L
23

Here's my solution. It works offline (so no call to an api). It's fast and the packages are widely used and available on Nuget.

string tzIana = TimeZoneLookup.GetTimeZone(lat, lng).Result;
TimeZoneInfo tzInfo = TZConvert.GetTimeZoneInfo(tzIana);
DateTimeOffset convertedTime = TimeZoneInfo.ConvertTime(DateTimeOffset.UtcNow, tzInfo);
Leucine answered 8/1, 2019 at 16:35 Comment(5)
What nuget package is this?Hardie
The NuGet packages appear to be GeoTimeZone and TimeZoneConvertor.Macintyre
They are indeed GeoTimeZone and TimeZoneConverter. I updated the code to simplify and make it work on all supported platforms, and to return a full DateTimeOffset.Alexandros
This is definitely a great solution. I wonder what happens when timezones are changed around the world over time? For example, a country might decide to ditch daylight savings and remain on summer time all year. Would these packages use that info from a Windows update, or would the packages need to be updated?Trivet
After reading the documentation, it appears that the packages would need to be updated if timezone data changes. Simply updating Windows would not be sufficient in this case.Trivet
K
8

You can do it using Google api for identifying current timezone.
.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);
    }
}

And then you can easily use your GetLocalDateTime(double latitude, double longitude, DateTime utcDate) method as it was shown in the example above:

public static void Main()
{
    var myDateTime = GetLocalDateTime(33.8323, -117.8803, DateTime.UtcNow);
    Console.WriteLine(myDateTime.ToString());
}
Kike answered 10/11, 2015 at 22:55 Comment(4)
it is a very good idea. Please check what I comment on the other answer that I got below yours. Is there anyway to fix that? I´d rather using the other method over than this one because this is a little tedious. But anyway if there´s no way, I will use your method.Persuader
@ctabuyo I think there is no other way.. To get local time we need to know the current location name that is standardised between frameworks and environments. That's why it's look ok to use some 3rd party service or some predefined database with locations->timezones data. Actually I don't know your case to suggest you something more useful approach. But I believe it's nice way to handle this business logic. as Google services is high availability service.Kike
As far as I know, all Google APIs have limits per 24 hours - especially number of requests. You should check those limits to avoid unexpected interruptions if you plan to use this code in production.Brantbrantford
Just to add that this code doesn't work as-is anymore. Google Map API now requires an account and you need to send your API key as a parameterTamishatamma
P
2

Finally this is how I fixed it, I needed to use the TimeZoneDb livery which traduces the IANA TimeZone to the Microsoft Format, so this is the code to do it:

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

Thanks to anyone who helped, both the solutions helped me a lot and maybe without them I couldn´t achieve it.

Thank you very much!!

Persuader answered 11/11, 2015 at 20:54 Comment(1)
TimeZoneDb is very very slow. And the package has some dependency problems.Bronchial
B
0

You can convert current UTC time to local time using the following code:

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();
Brantbrantford answered 10/11, 2015 at 22:49 Comment(2)
This is what I have tried so far, problem is that the livery that I am using to get the TimeZone name, gives me the name like this: "America/Chicago", so then the FindSystemTimeZoneById gives an error because it couldn´t find it.Persuader
@ctabuyo Yes, you can use this method only with windows time zones, but not with IANA time zones which are different.Brantbrantford
G
0

here my solution based on mixed solutions. Need RestSharp and NodaTime (both from 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);

}
Glorious answered 6/2, 2017 at 0:30 Comment(0)
A
-1

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>
Advisee answered 2/12, 2019 at 5:18 Comment(2)
You guys have to copy and paste the code and run in a new browser in order to track your current location first as the code snippet wouldnt allow us to promptAdvisee
Hope you guys appreciateAdvisee

© 2022 - 2024 — McMap. All rights reserved.