PDA

View Full Version : Getting timezones with google maps api



jadwal
06-23-2016, 04:43 AM
I have a prayer time table which gets its location( location name, longitude and latitude) from the google maps api.
Now the main things work without any hassle but just now i noticed that i'm missing out the timezone for a location that has been searched or displayed.
without the timezone most of the location have wrong prayer times when the timetable is showing.

Is their any possible way i can fetch the timezone with the longitude and latitude for the searched locations.

anyway this could be fixed without any big modifications to the code.

my html code:


<html>

<head>

<meta name="keywords" http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="description" http-equiv="Content-Type" content="text/html; charset=UTF-8">

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta content="width=device-width, initial-scale=1" name="viewport">
<meta content="IE=edge" http-equiv="X-UA-Compatible">

<link href="https://www.googledrive.com/host/0B6erKxlMnhFDaVNpbllPb2p3NkE?stylo.css" rel="stylesheet" type="text/css" />
<link href="https://www.googledrive.com/host/0B6erKxlMnhFDb2tPSHdrMG9yODQ?search.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="https://www.googledrive.com/host/0B6erKxlMnhFDeEE2U3BXTmZkQjA?PrayTimes.js"></script>

</head>

<script type="text/javascript">
/*Daily Prayer Timing Code Starts*/
function getPrayerTimings(latitude, longitude) {
prayTimes.setMethod('MWL');
prayTimes.adjust( {asr: 'Standard', isha: '90 min'} );
prayTimes.tune( {fajr: -90, shoroeq: 0, dhuhr: 0, asr: 0, maghrib: 0, isha: 0} );

var todayDate = new Date(); // today
function prayerTimings(offset) {
todayDate.setDate(todayDate.getDate() + offset);
var times = prayTimes.getTimes(todayDate, [latitude, longitude]);
var list = ['Fajr', 'Sunrise', 'Dhuhr', 'Asr', 'Maghrib', 'Isha'];
var html = '<table id="dailyTimeTable">';
html += '<tr class="qibla_map_bg_h"><td><span class="fajri"></span><br />الفجر<br />Fajr</td><td><span class="shoroeqi"></span><br />الشروق<br />Shoroeq</td><td><span class="dhuhri"></span><br />الظهر<br />Dhuhr</td><td><span class="asri"></span><br />العصر<br />Asr</td><td><span class="maghribi"></span><br />المغرب<br />Maghrib</td><td><span class="ishai"></span><br />العشاء<br />Isha</td></tr>';
for (var i in list) {
html += '<td class="qibla_map_bg_tr">' + times[list[i].toLowerCase()] + '</td>';
}
html += '</tr></table>';
document.getElementById('dailyTimeTable-Container').innerHTML = html;

function $(id) {
return document.getElementById(id);
}
}

function highlight() {
var date = new Date();
var thisminutes = date.getHours() * 60 + date.getMinutes();
//thisminutes = 1119;
var tbl = document.getElementById("dailyTimeTable")
var cells0 = tbl.rows[0].cells;
var cells1 = tbl.rows[1].cells;
var help = [];
for (var i = 0; i < cells1.length; i++) {
var currenttime = cells1[i].innerHTML.match(/([0-9][0-9]):([0-9][0-9])/);
if (currenttime) currentminutes = parseInt(currenttime[1]) * 60 + parseInt(currenttime[2]);
entry = {
currentminutes: currentminutes,
currentidx: i
};
help.push(entry);
}
help.sort(function (a, b) {
return a.currentminutes - b.currentminutes;
});
var foundnext = foundcurrent = false;
var inext = icurrent = -1;
for (var i = 0; i < help.length; i++) {
currentminutes = help[i].currentminutes;
currentidx = help[i].currentidx;
if (!foundnext && currentminutes > thisminutes) {
foundnext = true;
inext = currentidx;
}
if (currentminutes <= thisminutes) {
foundcurrent = true;
icurrent = currentidx;
}
}
if (!foundnext) inext = help[0].currentidx;
if (!foundcurrent) icurrent = help[help.length - 1].currentidx;
for (var i = 0; i < cells1.length; i++) {
if (i == inext) {
cells0[i].className = "next";
cells1[i].className = "next";
} else if (i == icurrent) {
cells0[i].className = "current";
cells1[i].className = "current";
} else {
cells0[i].className = "";
cells1[i].className = "";
}
}
window.setTimeout(highlight, 0)
}

prayerTimings(0);
highlight();
}
/*Daily Prayer Timing Code Ends*/
</script>

<form class="container">
<div class="flexContainer">
<button type="submit" class="button"><i class="fa fa-search" aria-hidden="true"></i></button>
<input type="text" id="search" name="search" placeholder="Search...">
<button type="submit" id="geo" class="button2"><i class="fa fa-map-marker" aria-hidden="true"></i></button>
</div>
</form>

<div class="qibla_map_bg">

<div id="map-html">
</div>
<div id="dailyTimeTable-Container"></div>


<script id="map-tmpl" type="text/x-jquery-tmpl">
<h4>{{city}}</h4>
</script>

</div>
<!-- Placed at the end of the document so the pages load faster -->
<script src="https://www.googledrive.com/host/0B6erKxlMnhFDT01GRS1wVFJuMk0?jquery.js"></script>

<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?libraries=places&sensor=false&key=AIzaSyDx6yESNHPjUqcO3Xyw4dkWGbr7zLHN72E"></script>


<script src="https://www.googledrive.com/host/0B6erKxlMnhFDYktyaHhtUFUzUGs?utils.js"></script>
<script src="https://www.googledrive.com/host/0B6erKxlMnhFDcTd5SjZCbzV6M2s?utils-geo.js"></script>
<script src="https://www.googledrive.com/host/0B6erKxlMnhFDQVRLbzJkNnFVTEk?mustache.js"></script>
<script src="https://www.googledrive.com/host/0B6erKxlMnhFDNGFGM0ZyeGNFdHc?main.js"></script>
<script>
var city = localStorage.getItem("city");
var lat = localStorage.getItem("latitude");
var lng = localStorage.getItem("longitude");
if (!city) {
city = "Amsterdam";
lat = 52.3702;
lng = 4.8952;
}
updateMap(city, lat, lng);
</script>

</body>

</html>

</body>

</html>

and my main js:


/**
* Created with JetBrains WebStorm.
* User: bilelz
* Date: 17/04/13
* Time: 22:24
* To change this template use File | Settings | File Templates.
*/

var isAutocompleted = false;

$(document).ready(function() {
autocompleteInit();
log("init");
/* search */
$('form').submit(function() {
if(!isAutocompleted){
$("#search").blur();
getLatlngFromCity($("#search").val());
log("typed from input search");
}

isAutocompleted = false; /* reset boolean value */
return false;
});


/* geo localisation */

// script for print geo link when focus in searchbox
// $("#search").focus(function() {
// $("#geo").addClass("show");
// });
// $("#search").blur(function() {
// $("#geo").removeClass("show");
// });

$("#geo").click(function(e) {
$("#geo").removeClass("show");
$("#container").removeClass("blur");

infoGeo("");
if(navigator.geolocation) {
navigator.geolocation.getCurrentPosition(successCallback, errorCallback);
} else {
infoGeo("Votre navigateur ne prend pas en compte la géolocalisation HTML5");
}

function successCallback(position) {

getCityFromCoord(position.coords.latitude, position.coords.longitude);

infoGeo("Géolocalisation réussie :-)");
infoHide();
};

function errorCallback(error) {
// if(getStorage("lastId") != undefined){
// id = getStorage("lastId");
// }else{
// id = "2988507" // Paris;
// }
// getWeatherById(id);

switch(error.code) {
case error.PERMISSION_DENIED:
infoGeo("L'utilisateur n'a pas autorisé l'accès sa position");
break;
case error.POSITION_UNAVAILABLE:
infoGeo("L'emplacement de l'utilisateur n'a pas pu être déterminé");
break;
case error.TIMEOUT:
infoGeo("Le service n'a pas répondu temps");
break;
}
};

return false;
});

/* geo localisation */

/* print on not #cityClearSearch button */
$("#search").keyup(function() {
if ($.trim($(this).val()) != "") {
$("#cityClearSearch").removeClass("hide");
} else {
$("#cityClearSearch").addClass("hide");
$(this).val(""); // trim space
}
});

$("#search").on("blur", function (){
$("#search").keyup();
});

$("#search").on("focus", function (){
$("#search").keyup();
});

/* end : print on not #cityClearSearch button */



$("#multiCityList").on("click", "a", function (){
$('#multiCityList').html("").hide();
updateMap($.trim($(this).text()), $(this).attr("lat"), $(this).attr("lng"));
return false;
});

$("#multiCityList").on("click",".removeCityList", function (){
$('#multiCityList').html("").hide();
});

$("*[type=reset]").on("click",function (){
$('#multiCityList').html("").hide();
});
});
function autocompleteInit() {


var map;
var geocoder;
var input = document.getElementById('search');
var options = {
types : ['(cities)']
};

var autocomplete = new google.maps.places.Autocomplete(input, options);

google.maps.event.addListener(autocomplete, 'place_changed', function() {
try {

var placeLat = getLatFromStr(autocomplete.getPlace().geometry.location.toString());
var placeLng = getLngFromStr(autocomplete.getPlace().geometry.location.toString());
updateMap($("#search").val(), placeLat, placeLng)
$("#search").val("").blur();
$('#multiCityList').html("").hide();
log("autocomplete");
isAutocompleted = true;
} catch(e) {
isAutocompleted = false;
$('form').submit();
log("catch maps autocomplete");
log(e);
}
});

google.maps.event.addDomListener(input, 'keydown', function(e) {
if (e.keyCode == 13) {
if (e.preventDefault) {
e.preventDefault();
} else {
/* nothing */
}
}
});
}

function updateMap(city, lat, lng){

getPrayerTimings(lat, lng);

localStorage.setItem("city", city);
localStorage.setItem("latitude", lat);
localStorage.setItem("longitude", lng);

var tmpl = $("#map-tmpl").html();
var html = Mustache.render(tmpl, {city:city, lat:lat, lng:lng});
$("#map-html").html("").append(html);
}

codepen link:
http://codepen.io/anon/pen/OXRqvr

jscheuer1
06-23-2016, 05:22 PM
You might be overthinking this. Your code gets its time from the local time of the user and displays the prayer times for that user. That is if I understand the prayer times are for certain local daily events like sunrise, sunset, etc. If so, the only problem would be if the user were in DST (daylight savings time or similar local conventions). Then they might be off by an hour. You can determine that if you have permission to get the users location, or you could just ask (have a checkbox for DST).

But maybe you have a different problem. In any case, javascript can get the local time offset from UTC (Greenwich), that can be converted over to whatever location you want. But it's tricky. The getTimezoneOffset() returns the number of minutes from Greenwich, example:


var todayDate = new Date(); // today
var offset = todayDate.getTimezoneOffset();
function prayerTimings(offset) {

That offset of minutes must be added to the local time to get the UTC (Greenwich) time. It accounts for DST if in effect locally. But then, if you want the time somewhere else (different from Greenwich and the user's local time) more calculation is needed.

The Google Maps API allows you to get the timezone information from a given lat/lng and timestamp, but it's a call to their server, so would be asynchronous. That means the data returned might not be available just when you want it (can usually be worked around, but best avoided if possible), and it requires you know the user's lat/lng, or at least the lat/lng of the location you want the timezone information for. It generally requires an API key (although I was able to play with it a little without using one locally) and is subject to usage limitations (fairly generous), so if you only need this information in a general way, best to just program it into your code and only query for it at those times when it might be affected by variables.

It works like so:


var lat = some number; //the latitude
var lng = some number; // the longitude
$.ajax({
url:"https://maps.googleapis.com/maps/api/timezone/json?location="+lat+","+lng+"&timestamp="+(Math.round((new Date().getTime())/1000)).toString(),
}).done(function(response){

if(response.timeZoneId != null){
//do something
}

});


In the "do something" area you have access to (if the request worked):

response.dstOffset - the number of seconds difference from UTC if DST is in effect, 0 if not
response.rawOffset - the number of seconds difference from UTC not counting DST
response.status - "OK" if the request was successful
response.timeZoneId - a string representing the timezone, ex: "America/Los_Angeles"
response.timeZoneName - the common name for the time zone, ex: "Pacific Standard Time"

This might be easier using PHP, where you could use date_sunset() to get the sunset time for a lat/lng pair and a timestamp. But that's the problem. How do you get an accurate timestamp for a remote location? Whatever method is used, that would be an issue. So you could still be off by maybe a minute. There's also always the issue from getting from local time (server or user) to destination time (if different from both of those).

jadwal
06-23-2016, 07:52 PM
Thank you very much for this great explanation. I do have PHP and asp but still prefer to use js for this timetable.
Tried adding a dst dropdown button but it seems it has no effect on the times when changing the dst.

what i have so far is this:
added this this to my html code:

<script type="text/javascript">
jQuery.noConflict();
(function( $ ) {
$(document).ready(function() {
$("#select_format, #method, #dst").change(function() {
check_again();
$(this).css("background-color","#fcfab1");
});


});
})( jQuery );

</script>


function getPrayerTimings(latitude, longitude) {
prayTimes.setMethod('MWL');
prayTimes.adjust( {asr: 'Standard', isha: '90 min'} );
prayTimes.tune( {fajr: -90, shoroeq: 0, dhuhr: 0, asr: 0, maghrib: 0, isha: 0} );

var todayDate = new Date(); // today
function prayerTimings(offset) {
todayDate.setDate(todayDate.getDate() + offset);
var dst = $('dst').value;
var times = prayTimes.getTimes(todayDate, [latitude, longitude], dst);
var list = ['Fajr', 'Sunrise', 'Dhuhr', 'Asr', 'Maghrib', 'Isha'];
var html = '<table id="dailyTimeTable">';
html += '<tr class="qibla_map_bg_h"><td><span class="fajri"></span><br />الفجر<br />Fajr</td><td><span class="shoroeqi"></span><br />الشروق<br />Shoroeq</td><td><span class="dhuhri"></span><br />الظهر<br />Dhuhr</td><td><span class="asri"></span><br />العصر<br />Asr</td><td><span class="maghribi"></span><br />المغرب<br />Maghrib</td><td><span class="ishai"></span><br />العشاء<br />Isha</td></tr>';
for (var i in list) {
html += '<td class="qibla_map_bg_tr">' + times[list[i].toLowerCase()] + '</td>';
}
html += '</tr></table>';
document.getElementById('dailyTimeTable-Container').innerHTML = html;

function $(id) {
return document.getElementById(id);
}
}


and the selection box:


<select id="dst" size="1" class="timing_select" style="margin-right:10px;" onchange="prayerTimings(0);">
<option value="auto" selected="selected">DST</option>
<option value="0">0</option>
<option value="1">1</option>
</select>

jadwal
06-23-2016, 07:55 PM
Back to the timezone problem. Can i not use a timezone js file with all the timezone data in it for most of the location when fetching the longitude and latitude . Is this even possible?

jscheuer1
06-23-2016, 08:28 PM
If you have one. Typically these are so complex, that they are hosted. You can access them, again a lag (not a real big deal, you already have lag due to consulting Google Maps for the lat lng, but we want to streamline this as much as possible). Do you have PHP? I'm not sure this is the best approach, but I'm looking into it. It looks promising. The problem I'm seeing is that my localhost server is EDT and, say I want to get sunrise for LA, it gives the time in EDT, not PDT. While it's easy in javascript (and presumably PHP) to get to Greenwich time from any local (javascript) or server (PHP) time, the trick is in getting from there to the remote location. A lookup of some kind appears to be needed. The Google API provides that, as do some other services. Google's is free within reasonable usage limits. How much traffic are you expecting?

Anyways, this information can probably be accessed and utilized more efficiently server side (PHP - again, do you have it available?), but it doesn't have to be.

jadwal
06-23-2016, 09:01 PM
I'm not getting a lot traffic so if it's simpler to use google maps api then i like to use that.
and yes php is available. I'm just starting to code But if we decide to use php i will have to figure out how to connect my prayer time code with my PHP.

jscheuer1
06-24-2016, 09:16 PM
OK, getting there. I think, unless you can see how to integrate this (my latest use of the Google Maps Timezone API) with your prayer code, I will have to learn that (the prayer code) to help you further. But, at least to give you hope, check this out:


<!DOCTYPE html>
<html>
<head>
<title>Current Time in lat/lng from lat/lng Using Google Maps API and jQuery</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
</head>
<body>
<div id="results"></div>
<script type="text/javascript">
function curTimefrmLatLng(lat, lng){
var ts = Math.round(new Date().getTime() / 1000);
var gmre = /[^\d]*$/;
$.ajax({
url:"https://maps.googleapis.com/maps/api/timezone/json?location="+lat+","+lng+"&timestamp="+ts.toString(10),
success: function(response){
if(response.timeZoneId != null){
window.console && console.log(response);
ts = ts + response.dstOffset + response.rawOffset;
gm = new Date(ts * 1000).toUTCString().replace(gmre, " " + response.timeZoneName);
$('#results').html('Current time in ' + response.timeZoneId + ' : ' + gm);
}
}
});
}
curTimefrmLatLng(34.0522, -118.2437); // running with LA's lat/lng
</script>
</body>
</html>

jadwal
06-25-2016, 01:16 AM
Wow that's all the time info we need. I found some code which i implemented in my main js and it seems everything is working. The code does look a lot like yours.

new code to my main js file i have placed my api key in the placeholder for testing


function updateMap(city, lat, lng){
var time = (new Date()).getTime() / 1000;
$.getJSON("https://maps.googleapis.com/maps/api/timezone/json?location=" + lat + "," + lng + "&timestamp=" + time + "&key=your_api_key", function (data) {
var tzinfo = data;
var offsethours = tzinfo.rawOffset / 3600;
if (tzinfo.dstOffset == 0) isdst = 0; else isdst = 1;
getPrayerTimings(lat, lng, offsethours, isdst)
});

localStorage.setItem("city", city);
localStorage.setItem("latitude", lat);
localStorage.setItem("longitude", lng);

var tmpl = $("#map-tmpl").html();
var html = Mustache.render(tmpl, {city:city, lat:lat, lng:lng});
$("#map-html").html("").append(html);
}


and my html code


function getPrayerTimings(latitude, longitude, tzoffset, isdst) {
/*Daily Prayer Timing Code Starts*/
prayTimes.setMethod('MWL');
prayTimes.adjust({
asr: 'Standard',
isha: '90 min'
});
prayTimes.tune({
fajr: -90,
sunrise: 0,
dhuhr: 0,
asr: 0,
maghrib: 0,
isha: 0
});
var todayDate = new Date();
function prayerTimings(offset) {
todayDate.setDate(todayDate.getDate() + offset);
var times = prayTimes.getTimes(todayDate, [latitude, longitude], tzoffset, isdst);
var list = ['Fajr', 'Sunrise', 'Dhuhr', 'Asr', 'Maghrib', 'Isha'];
var html = '<table id="dailyTimeTable">';
html += '<tr class="qibla_map_bg_h"><td><span class="fajr2"></span><br />الفجر<br /> Fajr</td><td><span class="fajr2"></span><br />الشروق<br />Shoroeq</td><td><span class="fajr2"></span><br />الظهر<br />Dhuhr</td><td><span class="fajr2"></span><br />العصر<br />Asr</td><td><span class="fajr2"></span><br />المغرب<br />Maghrib</td><td><span class="fajr2"></span><br />العشاء<br />Isha</td></tr>';
for (var i in list) {
html += '<td class="qibla_map_bg_tr">' + times[list[i].toLowerCase()] + '</td>';
}
html += '</tr></table>';
document.getElementById('dailyTimeTable-Container').innerHTML = html;

function $(id) {
return document.getElementById(id);
}
}


Take a look at the updated codepen link:
http://codepen.io/anon/pen/OXRqvr

timezone function is working great, but do you think it's better to have a dst button on the page where visitors could click on it to have dst on or off,.
Or is that not necessary to have with this new timezone code.

anyway please take a look and tell me if there are some modifications we can do to make this code complete or i am missing some functions.

jscheuer1
06-25-2016, 03:01 AM
It's too late right now for me to get into checking the details. I will look tomorrow or over the weekend. I can see that your code is a lot like my code, it's mostly just using a jQuery ajax shortcut ($.getJSON), whereas I was using the basic $.ajax call on a json object - as I say, pretty much the same thing.

If it's working though, that's pretty much it. I would be concerned about possible lags that might not be totally accounted for, things that might happen sometimes - that's part of what I mean by details. I will look at that later. And I already know they can be dealt with if they need to be.

But the reason I'm answering now is to say, as long as you're using this method, you don't need to ask the user about DST.

I'm wondering though if you should perhaps use the actual value. Right now you have:


if (tzinfo.dstOffset == 0) isdst = 0; else isdst = 1;

But some locations do not use 1 hour difference, some use 2 or 3 hours, some even use 1.5 hours. some might use other values. So I would think that, since this value, if it exists, is given in seconds, that should be utilized as seconds in the computation.

Similarly with:


var offsethours = tzinfo.rawOffset / 3600;

But it's a little different there. In any case though, some zones vary by 15 minutes, 45 minutes, or a half hour. As long as this is able to be carried through, it's fine. If not - best again to use the actual seconds.

As I say, details later. I just wanted you to get the basic idea. In most cases where zones are whole hours from UTC and DST is either 0 or 1 hour, it will work. But in some few cases some allowances will need to be made.

See also:

http://www.timeanddate.com/time/time-zones-interesting.html

And, I think you should still consider PHP - so much simpler, and probably more accurate, see (demo):

http://jscheuer1.com/demos/tidbits/time/sun_info.php

code:


<pre><?php
$lat = 34.0522;
$lng = -118.2437;
$time = time();
$timejson = file_get_contents("https://maps.googleapis.com/maps/api/timezone/json?location=$lat,$lng&timestamp=$time");
$timejson = json_decode($timejson);
echo "For: " . gmdate("D, d M Y H:i:s e", $time) . PHP_EOL . PHP_EOL;
echo "In {$timejson->timeZoneId}, {$timejson->timeZoneName} Zone:" . PHP_EOL . PHP_EOL;
$sunInfo = date_sun_info ( $time , $lat , $lng );
//print_r($sunInfo);
date_default_timezone_set($timejson->timeZoneId);
foreach($sunInfo as $key => $data){
echo "$key: " . date("D, d M Y H:i:s", $data) . PHP_EOL;
}
?></pre>