I am building a few things and one of them is a countdown timer, the countdown will never be over an hour so all I need to do is countdown minutes and seconds.
I have it partially working, but the problem is with the leading zeros. I got it to work in the seconds but not with the minutes.
Check out my example http://jsfiddle.net/cgweb87/GHNtk/
JavaScript
setInterval(function() {
var timer = $('span').html();
timer = timer.split(':');
var minutes = timer[0];
var seconds = timer[1];
seconds -= 1;
if (minutes < 0) return;
if (minutes < 10 && length.minutes != 2) minutes = '0' + minutes;
if (seconds < 0 && minutes != 0) {
minutes -= 1;
seconds = 59;
}
else if (seconds < 10 && length.seconds != 2) seconds = '0' + seconds;
$('span').html(minutes + ':' + seconds);
}, 1000);
HTML
<span>10:10</span>
What I want to happen is the countdown timer can begin anywhere under 1 hour, it will count down with leading zeros ie in this format;
08:49
46:09
And when it reaches the countdown to simply just display:
00:00
Thanks for any input, and I don't want to use plugins, I want to learn it.
setInterval returns an identity you can use later to clearInterval:
var interval = setInterval(function() {
/* snip */
$('span').html(minutes + ':' + seconds);
if (parseInt(minutes, 10) == 0 && parseInt(seconds, 10) == 0)
clearInterval(interval);
}, 1000);
And, to avoid the ever-increasing minutes -- 00000001:42 -- either:
change length.minutes to minutes.length in your prefix test.
cast the values to Numbers when retrieving -- var minutes = parseInt(timer[0], 10); -- and just test if (minutes < 10) ....
Taking option #2, here's an update: http://jsfiddle.net/BH8q9/
to check the length of a string, it is not
length.minutes
length.seconds
it is
minutes.length
seconds.length
Made a few simple changes to your code and it works as you'd like:
setInterval(function() {
var timer = $('span').html();
timer = timer.split(':');
var minutes = timer[0];
var seconds = timer[1];
seconds -= 1;
if (minutes < 0) return;
if (seconds < 0 && minutes != 0) {
minutes -= 1;
seconds = 59;
}
else if (seconds < 10 && length.seconds != 2) seconds = '0' + seconds;
if ((minutes < 10) && ((minutes+'').length < 2)) minutes = '0' + minutes;
$('span').html(minutes + ':' + seconds);
}, 1000);
I moved the if ((minutes < 10).... line down to happen after the minutes -= 1; otherwise at 9:59, you won't get the extra 0. Also length.minutes is the wrong way around, it'd need to be minutes.length -- but to make sure it's being treated as a string (which has a length, whereas a number doesn't), I added a blank string to it and then took the length of that.. This is what ((minutes+'').length < 2 does (checks that you have the leading zero).. This is really the best way to accomplish it, but it's the closest to your existing code.
I understand that an answer has already being accepted but would like to throw in my 2c: I like to avoid extra coding whenever possible. Using Jonathan Lonowski's approach, I would improve it like:
var interval = setInterval(function() {
var timer = $('span').html().split(':');
//by parsing integer, I avoid all extra string processing
var minutes = parseInt(timer[0],10);
var seconds = parseInt(timer[1],10);
--seconds;
minutes = (seconds < 0) ? --minutes : minutes;
if (minutes < 0) clearInterval(interval);
seconds = (seconds < 0) ? 59 : seconds;
seconds = (seconds < 10) ? '0' + seconds : seconds;
minutes = (minutes < 10) ? '0' + minutes : minutes;
$('span').html(minutes + ':' + seconds);
}, 1000);
Related
I have data in json from laravel backend which looks like: "03:30:00", "01:45:00", "00:15:00"
Is there an easy way to count them together in vuejs so its looks like this: "05:30:00"
So this is simple javascript.
If the time string is always going to look the same, you can do:
let times = ["03:30:00", "01:45:00", "00:15:00"]; // you can have an unlimited number of time strings
let hours = 0;
let minutes = 0;
let seconds = 0;
for (const i in times) {
const time = times[i];
let splitTime = (time + "").split(":"); // make sure it's a string
seconds += parseInt(splitTime[2]);
if(seconds > 59){ // make sure it only goes until 59
minutes++;
seconds = seconds % 60;
}
minutes += parseInt(splitTime[1]);
if(minutes > 59){ // make sure it only goes until 59
hours++;
minutes = minutes % 60;
}
hours += parseInt(splitTime[0]);
}
let totalTime = (hours < 10 ? "0" + hours : hours) + ":"
+ (minutes < 10 ? "0" + minutes : minutes) + ":"
+ (seconds < 10 ? "0" + seconds : seconds); // put the left side zeros
I am trying to create countdown timer between 2 dates but the time is lagging behind after a while.
My PHP backend returns the difference between current time and X time in the future, for example current time and 2 hours in advance. This difference is passed to my HTML frontent in a .countdown class in the following format 03:20:15 which I use a javascript function to countdown the difference. Here is my function:
$(".countdown").each(function() {
var $e = $(this);
var interval = setInterval(function() {
var timer2 = $e.html();
var timer = timer2.split(':');
var hours = parseInt(timer[0], 10);
var minutes = parseInt(timer[1], 10);
var seconds = parseInt(timer[2], 10);
--seconds;
minutes = (seconds < 0) ? --minutes : minutes;
hours = (minutes < 0) ? --hours : hours;
if(hours < 0) {
clearInterval(interval);
window.location.reload();
} else {
seconds = (seconds < 0) ? 59 : seconds;
seconds = (seconds < 10) ? '0' + seconds : seconds;
minutes = (minutes < 0) ? 59 : minutes;
minutes = (minutes < 10) ? '0' + minutes : minutes;
hours = (hours < 10) ? '0' + hours : hours;
$e.html(hours + ':' + minutes + ':' + seconds);
}
}, 1000);
});
The code works as expected but after a few minutes, lets say 2-3 minutes, if you refresh the page or open it in a new window you will see that the countdown timer was lagging behind by seconds/minutes. Does someone know what Im doing wrong?
You should compute the difference between (new Date()) and the target date. Use that difference and format new HTML string instead of parsing it to a hour, minutes, seconds value for decrementing.
details
The setInterval api specs suggest that delays due to CPU load, other tasks, etc, are to be expected.
https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers
Your handler is called at approximately equal intervals while you consider them to be exact. At first iteration the actual time may differ from a planed time by some small amount (let say 4ms). Yet you are changing your counter by 1000 ms. As many more iterations passed this difference accumulates and become noticeable. A few minutes is enough to make this happens.
If you, on the other hand, pre-compute the target date-time value and will use the difference between current time and the target time your code will not be sensible to api inexactness.
$(".countdown").each(function () {
var $e = $(this);
const totalSeconds = (dt) => Math.floor(dt.valueOf() / 1000);
const f1 = (timer2) => {
var timer = timer2.split(':');
var tdt = new Date().setHours(
parseInt(timer[0]) + tdt.getHours(),
parseInt(timer[1]) + tdt.getMinutes(),
parseInt(timer[2]) + tdt.getSeconds());
return totalSeconds(tdt);
};
const targetTime = f1($e.html());
setInterval(function () {
var timeSpan = targetTime - totalSeconds(new Date());
if (timeSpan < 0) {
window.location.reload();
} else {
var seconds = timeSpan % 60;
var totalMinutes = Math.floor(timeSpan / 60);
var minutes = totalMinutes % 60;
var hours = Math.floor(totalMinutes / 60);
$e.html(hours + ':' + minutes + ':' + seconds);;
}
}, 1000);
});
see also:
https://jsfiddle.net/8dygbo9a/1/
I'm trying to build a Pomodoro clock like http://codepen.io/GeoffStorbeck/full/RPbGxZ/. The value of seconds goes to NaN randomly and then returns to normal after starting 'break'.
$('#circle a').click(function() {
var timer = $('.time > span').html();
timer = timer.split(':');
var minutes = timer[0]; //Value of minutes
var seconds = timer[1]; //Value of seconds
var settimer = setInterval(function() {
seconds -= 1;
console.log(seconds);
if (seconds < 0 && minutes != 0) {
minutes -= 1;
minutes = String(minutes);
seconds = 59;
} else if (seconds < 10 && seconds.length != 2)
seconds = '0' + seconds;
if (minutes < 10 && minutes.length < 2)
minutes = '0' + minutes;
$('.time > span').html(minutes + ':' + seconds);
//Start break when session is completed
if (minutes == 0 && seconds == 0) {
$('.upper').find('h1').text('BREAK');
var time = $('#break').find('span').text();
$('.time > span').html('0' + time + ':00');
$('#circle a').trigger("click"); //Start timer for break
}
}, 1000);
});
Here's the link to the codepen
http://codepen.io/ibrahimjarif/pen/wMKJWN
How do I fix the NaN issue?
And is there any better way to implement this?
The code $('#circle a').trigger("click"); //Start timer for break recursively calls the function that was executing originally. This call starts a new timer while the original one was in progress.
The seconds value for the original timer went to NaN when the new timer was executing. There were two values for second due to two timers. The value of seconds in the original timer caused the unexplained appearance of NaN.
NOTE: Both the timers were running simultaneously all the time.
The simplest fix was to stop the current timer before starting a new one.
Here's the updated code
$('#circle a').click(function() {
var timer = $('.time > span').html().split(':');;
var minutes = Number(timer[0]),
seconds = Number(timer[1]);
var settimer = setInterval(function() {
seconds -= 1;
if (seconds < 0 && minutes != 0) {
minutes -= 1;
seconds = 59;
} else if (seconds < 10 && seconds.length != 2)
seconds = '0' + seconds;
if (minutes < 10 && minutes.toString().length < 2)
minutes = '0' + minutes;
$('.time > span').html(minutes + ':' + seconds);
if (minutes == 0 && seconds == 0) {
clearInterval(settimer); //Stop the current timer
var upper_text = $('.upper').find('h1');
var time;
if (upper_text.text() == 'BREAK') {
upper_text.text('Session');
time = $('#session').find('span').text();
} else {
upper_text.text('BREAK');
time = $('#break').find('span').text();
}
$('.time > span').html(time + ':00');
$('#circle a').trigger("click"); //Start new timer
}
}, 1000);
});
I'm making a stopwatch and out of esthetic reasons I want the output to display: 00:00:00:000. The problem is that when my stopwatch is running I'm having a hard time getting it to except a 0 in front when the value < 10.
window.addEventListener('load', function() {
var display = document.getElementById('display-area');
var toggle = document.getElementById('toggle-button');
var reset = document.getElementById('reset-button');
var ms,
difference,
interval,
hours,
minutes,
seconds,
timer = 0;
function start() {
difference = Date.now();
interval = window.setInterval(update, 10);
timer = 1;
};
function stopp() {
window.clearInterval(interval);
timer = 0;
};
function nullstill() {
ms = 0;
seconds = 0;
minutes = 0;
hours = 0;
display.value = '00:00:00:000';
};
function update() {
ms += elapsedTime();
if (ms >= 1000) {
seconds += 1;
ms = 0;
}
if (seconds >= 60) {
minutes += 1;
seconds = 0;
}
if (minutes >= 60) {
hours += 1;
minutes = 0;
}
display.value = hours + ':' + minutes +':' + seconds +':'+ ms;
};
function elapsedTime() {
var now = Date.now();
elapsed = now - difference;
difference = now;
return elapsed;
};
nullstill();
toggle.addEventListener('click', function() {
console.log(timer);
if (timer != 1) {
start();
} else {
stopp();
}
});
reset.addEventListener('click', function() {
nullstill();
});
});
How do I make it work?
Regards,
An integer will never hold a 0 in front of the number. This is a fairly easy fix. You will just need to use some string concatenation.
display.value = (hours < 10 ? "0"+hours : hours) + ':' + (minutes < 10 ? "0"+minutes : minutes) +':' + (seconds < 10 ? "0"+seconds: seconds) +':'+ ms;
The syntax I have used is called a ternary operator. Here is a little bit about how it works. Basically, it is a simplified if statement which can be used inline.
( condition ? {if true, run this } : {else, run this})
Here's a useful little example that shows you a convenient way to add leading zeros to numbers in Javascript. If you have a number like 53, and want 6 number places (eg 4 leading zeros in the case of 56), you just add (1e6+53+'').slice(-6) and that will give you 000053 because 1e6 means 1 with 6 zeros after it, and slice with a negative number starts from the end and chops out 6 places in this case, so 100000053 becomes 000053
hours=0,minutes=1,seconds=20,ms=7;
document.getElementById('t').innerHTML=
(1e2+hours+'').slice(-2) + ':' +
(1e2+minutes+'').slice(-2) +':' +
(1e2+seconds+'').slice(-2) +':'+
(1e3+ms+'').slice(-3);
<div id='t'></div>
Notice the 1 or 2 leading zeros in the case of ms is handled. And you can adjust the number of leading zeros easily.
This requires string concatenation when the value is less than 10. I would create three separate variables for the hours, minutes and seconds. That way the code is more clean and readable.
var displayHours = (hours >= 10) ? hours : "0" + hours;
var displayMins = (minutes >= 10) ? minutes : "0" + minutes;
var displaySeconds = (seconds >= 10) ? seconds : "0" + seconds;
display.value = displayHours + displayMins + displaySeconds + ":" + ms;
I want to stop this timer when I end the exam, but before it reaches zero. Kindly help me out on scripts please. Thanks.
JavaScript code:
var cnt = 165*60; // 165 minutes (2 hours & 45 minutes) convert to seconds
function countdown() {
if (cnt < 0) {
document.f.c.value = "- : - - : - -" ;
}
else {
hour = Math.floor(cnt / 3600);
totalmin = Math.floor(cnt / 60);
min = totalmin - (hour * 60);
sec = cnt - (totalmin * 60);
if (sec < 10) { sec = "0" + sec;}
if (min < 10) {min = "0" + min;}
if (hour < 10) {hour = "0" + hour;}
document.f.c.value = hour + ":" + min + ":" + sec;
cnt--;
_timer = setTimeout("countdown()", 1000);
}
}
var _timer = setTimeout("countdown()", 1000); // tick
I assume you meant that you want to end the timer before the countdown reaches 0.
First of all, you should use setInterval instead. It should work in all major browsers (including IE). It is just a slightly nicer way to express "I want this to happen every so often." According to the MDN, it:
Calls a function repeatedly, with a fixed time delay between each call to that function.
Here's how you would use it:
var cnt = 165*60; // 165 minutes (2 hours & 45 minutes) convert to seconds
function countdown() {
if (cnt < 0) {
document.f.c.value = "- : - - : - -" ;
}
else {
hour = Math.floor(cnt / 3600);
totalmin = Math.floor(cnt / 60);
min = totalmin - (hour * 60);
sec = cnt - (totalmin * 60);
if (sec < 10) {sec = "0" + sec;}
if (min < 10) {min = "0" + min;}
if (hour < 10) {hour = "0" + hour;}
document.f.c.value = hour + ":" + min + ":" + sec;
cnt--;
if(cnt <= 0) { # Stops the timer when it reaches 0.
clearInterval(_interval);
}
}
}
var _interval = setInterval(countdown, 1000);
And somewhere in your page have a button that will stop the timer.
<input type="button" value="Done" onclick="clearInterval(_interval)">
Although to be honest, having a countdown timer freaks me out. I'd rather have a count-up timer. :-)
In your else part
check
if(current_time < total_time)
{
//Set TimeOut
}
I think your best bet here is to use setInterval rather than setTimeout.
setInterval returns a handle to the interval. clearInterval(handle) will cancel that interval. Here's some pseudo to get you started:
var global_timer;
function countdown(){
// do some countdown stuff
if([we're done]) {
window.clearInterval(global_timer);
}
}
global_timer = window.setInterval("countdown()", 1000);
In the code that you execute when user ends the exam, probably after button click, just add such line:
window.clearTimeout(_timer);
And the timer will stop ticking.