I need to show the server time on a clock. Below is the code i currently have. I get the server time with Ajax call. The problem is that if the user changes it's local/puter clock it will also update the script's clock which is not ok - it should continue without changing and i'm stuck. I've tried passing the serverTime within the setTimeout so it get's used every time as a reference but no luck with that.
var serverTime = 1490856278000;
var localTime = +Date.now();
var timeDiff = serverTime - localTime;
var realTime;
var date;
var hours;
var minutes;
var seconds;
setInterval(function () {
realTime = +Date.now() + timeDiff;
date = new Date(realTime);
hours = date.getHours();
minutes = date.getMinutes();
seconds = date.getSeconds();
document.getElementById('clock').innerHTML = hours + ':' + minutes + ':' + seconds;
}, 1000);
<div id="clock"></div>
I need to show the server time on a clock. Below is the code i currently have. I get the server time with Ajax call. The problem is that if the user changes it's local/puter clock it will also update the script's clock which is not ok - it should continue without changing and i'm stuck. I've tried passing the serverTime within the setTimeout so it get's used every time as a reference but no luck with that.
var serverTime = 1490856278000;
var localTime = +Date.now();
var timeDiff = serverTime - localTime;
var realTime;
var date;
var hours;
var minutes;
var seconds;
setInterval(function () {
realTime = +Date.now() + timeDiff;
date = new Date(realTime);
hours = date.getHours();
minutes = date.getMinutes();
seconds = date.getSeconds();
document.getElementById('clock').innerHTML = hours + ':' + minutes + ':' + seconds;
}, 1000);
<div id="clock"></div>
Share
Improve this question
asked Mar 30, 2017 at 12:00
g5wxg5wx
7301 gold badge10 silver badges31 bronze badges
7
- you should periodically query the servers time, not just a single time. – Daniel A. White Commented Mar 30, 2017 at 12:03
- What is the problem with the user changing his local time? He can always break your page. – Bergi Commented Mar 30, 2017 at 12:03
- Yeah, but i don't want the clock to change if it does. – g5wx Commented Mar 30, 2017 at 12:03
-
1
Since your interval is every
1000ms
, you could reasonably expect it to run within a small window of that value. Compare theDate.now()
you get to whateverDate.now()
you got last time around, and if it changes by an unexpected amount (more than 1.5s, less than 0.5s, or negative, for example) then re-request the time from the server to recalibrate. – Niet the Dark Absol Commented Mar 30, 2017 at 12:03 -
1
Btw, you probably will want to use
getUTCHours
,getUTCMinutes
andgetUTCSeconds
instead of the local ones that could be tinkered with already by a changing time zone. – Bergi Commented Mar 30, 2017 at 12:06
4 Answers
Reset to default 3You should be able to pare each realTime
with the last one in your setInterval
. If the difference is far from the 1000ms that it is supposed to be, do an ajax call to query the server time again and renew the timeDiff
.
Also you can try to use performance.now
instead of Date.now
. The higher resolution is unnecessary and possibly expensive, but MDN states that
unlike
Date.now()
, the values returned byPerformance.now()
always increase at a constant rate, independent of the system clock (which might be adjusted manually or skewed by software like NTP)
Using How to create an accurate timer in javascript? and Bergi's answer I prepared an another way. I think you don't have to use the local time at all:
var serverTime = 1490856278000;
var expected = serverTime;
var date;
var hours;
var minutes;
var seconds;
var now = performance.now();
var then = now;
var dt = 0;
var nextInterval = interval = 1000; // ms
setTimeout(step, interval);
function step() {
then = now;
now = performance.now();
dt = now - then - nextInterval; // the drift
nextInterval = interval - dt;
serverTime += interval;
date = new Date(serverTime);
hours = date.getUTCHours();
minutes = date.getUTCMinutes();
seconds = date.getUTCSeconds();
document.getElementById('clock').innerHTML = hours + ':' + minutes + ':' + seconds;
console.log(nextInterval, dt); //Click away to another tab and check the logs after a while
now = performance.now();
setTimeout(step, Math.max(0, nextInterval)); // take into account drift
}
<div id="clock"></div>
The time will change because Date.now();
is getting it's time from the Client machine. There are no AJAX calls in your script.
More Updated with AM & PM
var serverTime = 1490856278000;
var expected = serverTime;
var date;
var h;
var m;
var s;
var now = performance.now();
var then = now;
var dt = 0;
var nextInterval = (interval = 1000);
setTimeout(step, interval);
function step() {
then = now;
now = performance.now();
dt = now - then - nextInterval;
nextInterval = interval - dt;
serverTime += interval;
date = new Date(serverTime);
h = date.getHours();
m = date.getMinutes();
s = date.getSeconds();
var session = "AM";
if (h == 0) {
h = 12;
}
if (h > 12) {
h = h - 12;
session = "PM";
}
h = h < 10 ? "0" + h : h;
m = m < 10 ? "0" + m : m;
s = s < 10 ? "0" + s : s;
var time = h + ":" + m + ":" + s + " " + session;
document.getElementById("NowTime").innerHTML = time;
now = performance.now();
setTimeout(step, Math.max(0, nextInterval));
}