The following code is a countdown timer. It pulls an ending datetime stamp from mySQL and uses it to count to. The issue is that the mysql time may be in a different time zone than the client who is looking at the page with the timer.
I also pull the current timestamp from mySQL with NOW(), thinking that this would allow the timer to count as the user who created it intended.
if I put the NOW() value in this snippet
var timeDiff = target - (new Date());
like so
var nt='2015-03-11 05:12:15'.split(/[- :]/);
var timeDiff = target - (new Date(nt[0],nt[1]-1,nt[2],nt[3],nt[4],nt[5]));
the counter shows the correct time left when the page loads but does not count interactively any longer. I think I need to get the difference in hours between the clients local time and the mySQL NOW() and adjust the date in this line to get the interactive timer to run.
var timeDiff = target - (new Date());
nothing I try seems to work.
This is the working script if the client happens to be int he same time zone.
<script language="javaScript">
document.write(hrs);
function timeDiff(target) {
function z(n) {return (n<10? '0' : '') + n;}
var timeDiff = target - (new Date());
var hours = timeDiff / 3.6e6 | 0;
var minutes = timeDiff % 3.6e6 / 6e4 | 0;
var seconds = timeDiff % 6e4 / 1e3 | 0;
if (hours<0 || minutes<0 || seconds<0) {
document.getElementById('divBody').style.display='none';
document.getElementById('divExpired').style.display='';
return '<b>EXPIRED</b>';
}
else {
return '<b>' + z(hours) + '</b> Hours, <b>' + z(minutes) + '</b> Mins, <b>' + z(seconds) + '</b> Secs';
}
}
function doCountDown(target) {
document.getElementById('timer').innerHTML = '<img src=\"/backhaul/images/my/al-active.png\" class=\"vm2\" /> <span style=\"color:#c40000\"><b>EXPIRES IN</b></span>: ' + timeDiff(target);
var lag = 1020 - (new Date() % 100);
setTimeout(function(){doCountDown(target);}, lag);
}
window.onload = function() {
//Insert Expiratin Date from mySQL into t var
var t='2015-03-12 00:00:00'.split(/[- :]/);
doCountDown(new Date(t[0],t[1]-1,t[2],t[3],t[4],t[5]));
}
</script>
There are many ways of doing this, but I'll elaborate on two ways.
Method 1 : Adjust the time on the client side
One way is what you are trying to do which is to get the current time of the server and find the difference with the client's current time. You can simply adjust the server target time to the client's time. This can be done with
var serverDifference=Date.parse(mysql_data.now)-Date.now()
var target=Date.parse(mysql_data.server_time_in_two_hours)-serverDifference
Then you can input it into your function without problem.
Method 2: Calculate the times remaining, server side
Since you just need a countdown timer, I think it's more appropriate to simply send the seconds left server side. This can be done with SQL using
select timestampdiff(SECOND,now(),end_time) seconds_left from timers;
Then you simply just make a timer that counts down based on the number of seconds left instead of a target date. You can calculate the number of seconds left by deducting the time that the javascript has run from the time received from the server. So something like
var client_start=Date.now()
function timeDiff_fromseconds(target) {
function z(n) {return (n<10? '0' : '') + n;}
var timeDiff =target-(Date.now()-client_start)
var hours = timeDiff / 3.6e6 | 0;
var minutes = timeDiff % 3.6e6 / 6e4 | 0;
var seconds = timeDiff % 6e4 / 1e3 | 0;
if (hours<0 || minutes<0 || seconds<0) {
return '<b>EXPIRED</b>';
}
else {
return '<b>' + z(hours) + '</b> Hours, <b>' + z(minutes) + '</b> Mins, <b>' + z(seconds) + '</b> Secs';
}
}
There is also performance.now() as suggested by #dandavis. This returns the number of milliseconds since the tab opened and is accurate to 1/1000th of a millisecond. And this doesn't change even if the system clock of the client browser changes. For full support, you should use a polyfill (As of the time of this writing, iOS Safari doesn't support it). In this context we can replace Date.now() with it.
JSFiddle Demo:
http://jsfiddle.net/3o3u5r5j/1/
If it is possible to get remaining amount of seconds from database instead of expiry time (meaning to calculate it at the server and send to the client). Then you can use following code (sample). Fiddle
var countDownId;
var timer;
function countDown(){
console.log(timer--);
if(timer<=0){
clearInterval(countDownId);
alert('time expired');
}
}
function startCountDown(secondsToExpire){
var milliseconds = 1 * 1000 ;// 1 second
timer = secondsToExpire;
countDownId = setInterval(function() { countDown();},milliseconds);
}
window.onload = function() {
//Insert remaining time from expiration
var timeRemaining = 5;
startCountDown(timeRemaining);
}
You can tweak this to suit your needs.
Related
I am creating a website for students which will be used to assign exams and I am having difficulties with the timer. The one I am using is made on the frontend in javascript and whenever the page is refreshed the timer startsover. Tried to store the start and end date by converting to epoch and back to datetime but I cannot think of a way to get the timer to the frontend and start counting. The idea is to count 60 minutes and call the submit button as well as to show the countdown without the option to restart the counter.
This is how I store the start and end time in nodejs.
var myDate = new Date();
var startTimeEpoch = myDate.getTime()/1000.0;
var endTimeEpoch = startTimeEpoch + 5400 // Adding 90 minutes to the timer
var startTimeBackToDate = new Date(startTimeEpoch *1000)
var endTimeBackToDate = new Date(endTimeEpoch *1000)
This is the javascript timer I am using and I am wondering if I should use one in the first place.
function startTimer(duration, display) {
var start = Date.now(),
diff,
minutes,
seconds;
function timer() {
diff = duration - (((Date.now() - start) / 1000) | 0);
minutes = (diff / 60) | 0;
seconds = (diff % 60) | 0;
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display.textContent = minutes + ":" + seconds;
if (diff <= 0) {
start = Date.now() + 1000;
}
}
timer();
setInterval(timer, 1000);
}
window.onload = function () {
var fiveMinutes = "<%= scenario.time %>" * 60,
display = document.querySelector('#time');
startTimer(fiveMinutes, display);
}
As a general response and with the additional information provided, i could propose a solution to make this work.
If your students all have a specific exam entity attached to them, when they register/start an exam, you could retrieve the start date of this exam(add a mongo createdAt Date field) and use it as the starting date.
If each exam has a time limit, then you could simply do the math to know how much time is left. Something that will look like this:
const getExamRemainingTime = (exam) => {
// assuming that start is a js date object
// and timeLimit is an number representing the duration hours of your exam
const { start, timeLimit } = exam;
let end = (start.getHours() + timeLimit);
end = end.setHours(end);
const remainingTime = (+end) - (+start)
if (remainingTime > 0) {
// duration not finished, exam still in progress
return new Date(remainingTime);
} else {
// exam finished
return 0;
}
}
Then in your frontend, if it's plain javascript, you need to refresh your timer component, use setInterval in last ressort because it's very heavy on performance and format the date you got the way you want to show it.
Ref: casting js Date object to timestamp - How do you get a timestamp in JavaScript?.
I don't think a timer that a student with Javascript knowledge can modify should be used for serious tests, but for anything more light-hearted it should be fine.
The best system I can think of for this would be to have the test length stored in the mongodb and when a signed-in user starts the test, have the current time logged for that user. That way, you can calculate time remaining using user.testStart + test.length - Date.now().
Here's the scenario, I have a time that counts the time_taken by a user. What I want is to get the exact time_taken based from the timer. For example, a user take an exam, then after he/she take the exam, the time_taken will be submitted (e.g. 1hr 25mins 23secs). Please see my code below.
$(document).ready(function(){
var d;
setInterval(function(){
d = new Date();
dates = d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds();
$('#timeTaken').val(dates);
}, 1000);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" id="timeTaken" value="">
Here is Fiddle for the solution
https://jsfiddle.net/djzsddz6/1/
Ans Solution is below:
$(document).ready(function(){
var seconds = 0, minutes = 0 , hours = 0;
setInterval(function(){
seconds++;
if(seconds == 60){
minutes++
seconds = 0;
}
if(minutes == 60){
hours++
minutes = 0;
}
console.log(hours, minutes, seconds);
$('#timeTaken').val(`${hours}:${minutes}:${seconds}`);
}, 1000);
});
I don't really see the point to use an input there, you can just display in a span and when the form gets submitted take the time elapsed and send it with other data. Anyways, this should work for you:
$(document).ready(function () {
var time_start = new Date();
setInterval(function () {
var time_end = new Date();
var time_diff = (time_end - time_start);
// hours
var hours = Math.floor(time_diff / 1000 / 60 / 60);
// minutes
time_diff = time_diff - hours * 1000 * 60 * 60;
var minutes = Math.floor(time_diff / 1000 / 60);
// seconds
time_diff = time_diff - minutes * 1000 * 60;
var seconds = Math.floor(time_diff / 1000);
renderTime(hours, minutes, seconds);
}, 1000);
});
function renderTime (hrs, min, sec) {
var str = convertTime(hrs) + ":" + convertTime(min) + ":" + convertTime(sec);
$("#timeTaken").val(str);
}
function convertTime (val) {
return val < 10 ? "0" + val : val;
}
What's going on here is we have the time_start which does not change and we have setInterval function that is triggered every second. There we create new Date object, and the subtract the static one from it, which returns the time difference in milliseconds. We do the weird Math.flooring and subtracting, so we can have hours, minutes and seconds as an integers (not floats). Then we use render function to display the time inside an desired element.
Why I think it's a better solution then the others are, is that if you want to handle the user's page refresh you just need to save one variable to cookie or something else and it will work regardless of the page refresh.
Handling the page refresh would look like (with cookie saved for 2 hrs):
function updateTimeCookie () {
var time_now = new Date()
var value = JSON.stringify(time_now);
var expires = time_now.setTime(time_now.getTime() + 7200);
$.cookie("timeStart", value, { expires: expires });
};
// to get Date object from cookie: new Date(JSON.parse($.cookie("timeStart")))
To use $.cookie() you must first include jQuery Cookie Plugin.
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
Working fiddle without cookie: https://jsfiddle.net/qc3axmf4/1/
Working fiddle with cookie: https://jsfiddle.net/ta8bnzs0/2/
Rather than getting date at every second you can keep the counter in set interval which will updated at every second. At the time of submission you can perform division and modulus operation to get exact time taken
Example
$(document).ready(function(){
var timer =0;
setInterval(function(){
Timer +=1;
// Code for display in hr mm and ss
$('#timeTaken').val(dates);
}, 1000'
});
You can also convert second in time valueby using moment.js
Hope this helps you.
Happy coding
I need some advice and logic in my problem.
So, I have an entrydate, from database, then the running current date, and a value of 10(double type in database). So, I know how to calculate the diff of the entrydate and current date, right. So I convert it to seconds then to a number(9.23165).
|Entry |Current Date|Diff(in number)|
|2:00:00 PM |2:30:00 PM | 5.00(Sample)|(First User)
So basically, as current date goes on, can PHP show the deduction on real time? Or I need to refresh? What I need is for it to display the deduction without refreshing. So basically, I need to know what I have to do. Maybe javascipt and ajax?
What you would need are a few Javascript/jQuery functions to update the browser in real time.
var myTimer;
var startTime;
function startTimer() {
stopTimer(); // Reset
startTime = new Date(); // Save to calculate difference
myTimer = setInterval(clockTicking, 1000);
}
function stopTimer() {
clearInterval(myTimer);
}
function clockTicking() {
var now = new Date();
var timeDiff = new Date(now - startTime); // constructor uses UTC, so use UTC date functions from here on
var hours = (timeDiff.getUTCHours() < 10) ? '0' + timeDiff.getUTCHours() : timeDiff.getUTCHours();
var mins = (timeDiff.getUTCMinutes() < 10) ? '0' + timeDiff.getUTCMinutes() : timeDiff.getUTCMinutes();
var secs = (timeDiff.getUTCSeconds() < 10) ? '0' + timeDiff.getUTCSeconds() : timeDiff.getUTCSeconds();
$("<element-where-you-display>").html(hours + ':' + mins + ':' + secs);
}
In Javascript you can call startTimer() to kick it off.
i want to fire an event on specific date and time in javascript. for example ,
if current date and time is 19-11-2015 10:00 AM , and i set a timer on 19-11-2015 10:30 AM then , it should fire after 30 minutes. here set timer date could be after two days also.
my current code is as follows.
setTimer :function(hr , min){
var d1 = new Date();
var d2 = new Date();
console.log("Time 1 "+d1.getTime());
d2.setMinutes(d1.getMinutes() + min);
d2.setHours(d1.getHours() + hr);
console.log("Time 2 "+d2.getTime());
setTimeout(function(){
alert("called");
},d2.getTime());
alert("Before " + d1.getDate() + " - "+d1.getMonth() + " - "+d1.getFullYear() + "<>"+d1.getHours()+ ":"+d1.getMinutes()
+ "\n" +
"After " + d2.getDate() + " - "+d2.getMonth() + " - "+d2.getFullYear() + "<>"+d2.getHours()+ ":"+d2.getMinutes() );
},
i called it using setTimer(0,1); to fire a timer after one minute but its not getting fired.
Find out the time remaining using Date function and then pass it on to setTimeout function.No need to keep on checking the time.
$(document).ready(function(){
var d = new Date("November 19, 2015 17:00:00");
var d1 = new Date();
var timelimit = (d.getTime() - d1.getTime());
if(timelimit > 0) {
setTimeout(function(){
console.log(12345);
},timelimit);
}
});
Using setTimeout is not a reliable way to create timers.
You're much better off using setInterval and checking whether you've reached the correct time yet.
function setTimer(hours, minutes) {
var now = Date.now();
// work out the event time in ms
var hoursInMs = hours * 60 * 60 * 1000,
minutesInMs = minutes * 60 * 1000;
var triggerTime = now + hoursInMs + minutesInMs;
var interval = setInterval(function() {
var now = Date.now();
if(now >= triggerTime) {
alert('timer!');
// clear the interval to avoid memory leaks
clearInterval(interval);
}
}, 0);
}
You'll save yourself a lot of bother if you use Date.now which returns the date as the number of milliseconds since the epoch. Then you can just treat the problem numerically, rather than messing with the date api.
Im using this jquery plugin for time count down in my web app. Please help me out to remain the count down time not beginning at first each time.I want to set the cont down for a month (30 days 24h 60min 60 sec).So every time i refresh count down should not be started from the beginning.Thnx
here is the script code to set the time
$('#counter').countdown({
timestamp : (new Date()).getTime() + 30*24*60*60*1000
});
Does everyone need the same end time? For example, if you want to launch your site on March 5, 2014 at 5 PM Eastern, then you want to set the launch time like so:
var ts = new Date(Date.UTC(2014, 2, 7, 22))
$('#counter').countdown({
timestamp : ts
});
Alternatively, if each user needs to see a unique countdown, then you want to persist the time in a cookie. For example, if I open the page 5 minutes after you open the page. Should the timer be 5 minutes apart? If yes, then use the cookie. If no and both of our timers should be the same, then pass to the counter the desired end date.
Note: UTC is set if timezones matter for you.
var today = new Date()
var enddate = new Date(2014,05,01)
function calcDate(date1,date2) {
var datadiff = Math.abs(date1 - date2) / 1000;
// calculate (and subtract) whole days
var days = Math.floor(datadiff / 86400);
datadiff -= days * 86400;
// calculate (and subtract) whole hours
var hours = Math.floor(datadiff / 3600) % 24;
datadiff -= hours * 3600;
// calculate (and subtract) whole minutes
var minutes = Math.floor(datadiff / 60) % 60;
datadiff -= minutes * 60;
// what's left is seconds
var seconds = Math.floor(datadiff % 60);
var message = " ";
message += days + " days " ;
message += hours + " hours ";
message += minutes + " minutes \n";
message += seconds + " seconds \n";
return message
}
a = calcDate(enddate,today);
alert(a);
If you need persistence, rather than creating a new date object in javascript, pass the date from the backend which should be saved the first time you start the countdown.
There are many ways to persist data. One way might to to store the date into a cookie.
function getCookie(name) {
var value = "; " + document.cookie;
var parts = value.split("; " + name + "=");
if (parts.length == 2) return parts.pop().split(";").shift();
}
date = getCookie('date');
if(!date) {
document.cookie="date=" + new Date().getTime() + 30*24*60*60*1000 + ";";
date = getCookie('date');
}
alert(date);
That should help you persist the date between browser refreshes, but only as long as the cookie lasts.