I'm new to JS and I'm stuck trying to figure out what's causing my countdown timer not to countdown. The user enters the time in 00:00:00 format minutes, seconds, and milliseconds. Afterwards, I convert that format to seconds to begin the process of counting down. I think the calculations is fine, but something is not causing it not to behave as it should be. I've tested and see that the code runs in terms of entering the time and showing up in the output. I see the countdown decrementing, for both seconds and milliseconds at the same time but it should go from 10:00:00 to 09:59:99.. 09:59:98... Basically seconds won't change until milliseconds reaches zero. so 09:59:00 will be 09:58:99... Please any help is greatly appreciated. I've been going at this and been stuck.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script type="text/javascript">
var running = 0; //Glob variable for starting/pausing timer
function startPause(){
var time = document.getElementById("timeEntered").value; //Not sure if needed but I just have the time entered be converted to seconds.
var a = time.split(":");
var timeToSeconds = (+a[0]) * 60 + (+a[1]) * 60 + (+a[2]);
if(running == 0){ //If off, turn it on.
running = 1;
countDown();
document.getElementById("startPause").innerHTML = "Start/Stop";
}else{
running = 0;
document.getElementById("startPause").innerHTML = "Resume";
}
}
function countDown() {
var time = document.getElementById("timeEntered").value; //Take user input and convert 00:00:00 format to seconds.
var a = time.split(":");
if(!timeToSeconds)
var timeToSeconds = (+a[0]) * 60 + (+a[1]) * 60 + (+a[2]);
if(running == 1){ //When user clicks start it will calculate the minutes, seconds, and milliseconds.
var minutes = Math.floor(timeToSeconds / 60);
var seconds = timeToSeconds % 60;
var milli = timeToSeconds % 100;
if(minutes <= 9) { //Add leading zeroes to display countdown in 00:00:00 format.
minutes = "0" + minutes;
}
if(seconds <= 9) {
seconds = "0" + seconds;
}
if(milli <= 9) {
milli = "0" + milli;
}
timeToSeconds--; //Decrement the time entered.
console.log(timeToSeconds);
document.getElementById("output").innerHTML = minutes + ":" + seconds + ":" + milli //Display the time 00:00:00 format.
if(timeToSeconds !== -1){
setTimeout('countDown()',100);
}
if(timeToSeconds == 0){ //When time is 00:00:00 the message will show.
document.getElementById("output").innerHTML = "The time is over."
}
}
}
</script>
</head>
<body>
<h1>Countdown Timer</h1>
<div id="mainCont">
<input type="text" id="timeEntered">
<p>
<button id="startPause" onclick="startPause()">Start/Stop</button>
</p>
<div id="output">00:00:00</div>
</div>
</body>
</html>
There are a handful of problem here, so I will go over each one and show you the solution. The first problem is that the value of timeToSeconds is the same on each iteration. The reason for this is because you are getting the value from the same unchanging source, decrementing does nothing as the value is lost on the next function call. To fix this have your function take a parameter in which you pass the remaining seconds off after you modified it:
function countDown(timeToSeconds) {
...
timeToSeconds-=0.1; //Decrement the time entered.
if(timeToSeconds <= 0){ //When time is 00:00:00 the message will show.
document.getElementById("output").innerHTML = "The time is over."
return;
}
else if(timeToSeconds !== -1){
setTimeout(function(){countDown(timeToSeconds)},100);
}
Notice I only subtracted 0.1 because our setTimeout is called after 100 milliseconds (0.1 seconds). I've also switched around the checks, as before hand you would call the timer even if timeToSeconds was 0.
The next thing was you conversion to seconds was off, in your code here:
var timeToSeconds = (+a[0]) * 60 + (+a[1]) * 60 + (+a[2]);
Both minutes and seconds are calculated in the same way, a[1] is the seconds value and should not be multiplied. And a[2] is actually 10*milliseconds (1 seconds = 1000 milliseconds). That value should be divide by 100:
if(!timeToSeconds)
var timeToSeconds = (+a[0]) * 60 + (+a[1]) + (Math.floor(+a[2]/100));
The if-statement is a basic check if the value is true (being any number). In our case it can work as a "Does this value exist" check, since we are only dealing with positive numbers. And the following conversions should be:
var minutes = Math.floor(timeToSeconds / 60) % 60;
var seconds = Math.floor(timeToSeconds) % 60;
var milli = Math.floor(timeToSeconds*100) % 100;
For the most part, your values for minutes and seconds where correct. Although the reason why milli and seconds appeared the same was because you never converted milli to it's correct value, as such they will have the same value apart from the % applied.
Here is the final result
One last thing I would like to point out is that this timer will not be exact. As it takes some time between the computation and the setTimeout call. For a more accuracy value you will want to use Date.now() and find the different between the start time and the current timer. This question uses such a method to do so, which can be applied to the countdown timer in the same fashion.
Related
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 a simple countdown timer, but it is really bugging me that I can't seem to get it for some reason, and I think it's because of the special way I need it done, it has to adhere to these rules:
Must be every hour
Must be on the 30 minute mark
Must use UTC time
So for instance, it is 07:22 UTC, it would be 8 minutes till the next one.
If it were say, 07:30, it would say 1 hour till the next one.
And last but not least, if it were 07:31, it would say 59 minutes till the next one.
I was able to do this very easily for other countdowns I made, but those were for on the hour type things, it wasn't this complicated... I'm just stumped big time, please help me.
EDIT
Added sample code
var d = new Date();
var hoursUntil = 2 - d.getUTCHours() % 3;
var minutesUntil = 60 - d.getUTCMinutes();
var timestr = "";
if (minutesUntil === 60) {
hoursUntil++;
minutesUntil = 0;
}
if (hoursUntil > 0) {
timestr += hoursUntil + " hour" + (hoursUntil > 1 ? "s" : "");
}
if (hoursUntil >= 1 && minutesUntil > 1) {
timestr += " and " + minutesUntil + " minute" + (minutesUntil > 1 ? "s" : "");
}
if (minutesUntil > 1 && hoursUntil < 1) {
timestr += minutesUntil + " minute" + (minutesUntil > 0 && minutesUntil < 2 ? "" : "s");
}
bot.sendMessage(msg, "Next event will be in " + timestr + ".");
Let's do some thoughts. What we want to know is, when the minute hand next time shows 30. If we wanted to know only every half hour, we could just take the rest of division by 30 as you did with d.getUTCHours() % 3.
However, we want to get every 60 minutes, so we have do do somethingInMinutes % 60. The mark must be on shift from 60 to 0, so just add 30 minutes.
To have seconds precision, calculate that into seconds, add the current seconds and subtract both from 60 minutes (3600 seconds).
We want a timer that triggers on every second shift. Calculate the difference of 1000 and milliseconds.
<div>Seconds remaining until next 30 minutes mark: <span id="min-total"></span></div>
<div>minutes:seconds remaining: <span id="min-part"></span>:<span id="sec-part"></span></div>
<script>
var byId = document.getElementById.bind(document);
function updateTime()
{
var
time = new Date(),
// take 1800 seconds (30 minutes) and substract the remaining minutes and seconds
// 30 minutes mark is rest of (+30 divided by 60); *60 in seconds; substract both, mins & secs
secsRemaining = 3600 - (time.getUTCMinutes()+30)%60 * 60 - time.getUTCSeconds(),
// integer division
mins = Math.floor(secsRemaining / 60),
secs = secsRemaining % 60
;
byId('min-total').textContent = secsRemaining;
byId('min-part').textContent = mins;
byId('sec-part').textContent = secs;
// let's be sophisticated and get a fresh time object
// to calculate the next seconds shift of the clock
setTimeout( updateTime, 1000 - (new Date()).getUTCMilliseconds() );
}
updateTime();
</script>
Maybe I am missing something but as far as I can see, UTC and in fact hours in general are not relevant to this. It should be as simple as just calculating where the current minute is.
Maybe something like
now = new Date();
minutes = now.getMinutes();
if(minutes > 30) {
minutes_until = (60 - minutes) + 30;
}
else {
minutes_until = 30 - minutes;
}
I am trying to make a small question/answer quiz game using react, and I want to show a timer that counts down every second. Each game will last 10, 15, or 30 minutes at most, so I want to show a timer that updates every second in the bottom of the screen (in big font, of course!), something like 15:00, 14:59, 14:58, and so on until it hits 00:00.
So, given a start time such as 2016-04-25T08:00:00Z, and an end time after adding 15 min of 2016-04-25T08:15:00Z, I want to start the countdown.
My issue is that I am not understanding how to use setIntervals to keep calling my method to find the remaining time.
timeLeft = Math.round(timeLeft/1000) * 1000;
const timer = new Date(timeLeft);
return timer.getUTCMinutes() + ':' + timer.getUTCSeconds();
EDIT: You've edited your question. You will need the time padding, and the method below will be faster than what you are using, but to answer your question about setInterval:
First, define your function to run your timer and decrement each time it's called:
var timeLeft; // this is the time left
var elem; // DOM element where your timer text goes
var interval = null; // the interval pointer will be stored in this variable
function tick() {
timeLeft = Math.round(timeLeft / 1000) * 1000;
const timer = new Date(timeLeft);
var time = timer.getUTCMinutes() + ':' + timer.getUTCSeconds();
elem.innerHTML = time;
timeLeft -= 1000; // decrement one second
if (timeLeft < 0) {
clearInterval(interval);
}
}
interval = setInterval(tick, 1000);
OG Answer:
No, I do not believe there is a built-in way to display time differences.
Let's say you have two date objects:
var start = Date.now();
var end = Date.now() + 15 * 60 * 1000; // 15 minutes
Then you can subtract the two Date objects to get a number of milliseconds between them:
var diff = (end - start) / 1000; // difference in seconds
To get the number of minutes, you take diff and divide it by 60 and floor that result:
var minutes = Math.floor(diff / 60);
To get the number of seconds, you take the modulus to get the remainder after the minutes are removed:
var seconds = diff % 60;
But you want these two padded by zeros, so to do that, you convert to Strings and check if they are two characters long. If not, you prepend a zero:
// assumes num is a whole number
function pad2Digits(num) {
var str = num.toString();
if (str.length === 1) {
str = '0' + str;
}
return str;
}
var time = pad2Digits(minutes) + ':' + pad2Digits(seconds);
Now you have the time in minutes and seconds.
I've a problem when running this script for my JavaScript countdown (using this plugin). What it should do is take the starting time, the current time and the end time and display the remaining time.
If I set these values with normal numbers in epoch time everything works just fine, but my question is: How do I set the current time and the start to be the real current one so that the countdown will be dynamic?
I've found this line: Math.round(new Date().getTime()/1000.0);
But I don't know how to make it work, considering I'm running this script at the bottom of my HTML file, before the </html> tag.
This is the script:
<script>
$('.countdown').final_countdown({
start: '[amount Of Time]',
end: '[amount Of Time]',
now: '[amount Of Time]'
});
</script>
This is how I tried to solve it, but it's not working:
//get the current time in unix timestamp seconds
var seconds = Math.round(new Date().getTime()/1000.0);
var endTime = '1388461320';
$('.countdown').final_countdown({
start: '1362139200',
end: endTime,
now: seconds
});
It sounds like you would like to count down from the current time to some fixed point in the future.
The following example counts down and displays the time remaining from now (whenever now might be) to some random time stamp within the next minute.
function startTimer(futureTimeStamp, display) {
var diff;
(function timer() {
// how many seconds are between now and when the count down should end
diff = (futureTimeStamp - Date.now() / 1000) | 0;
if (diff >= 0) {
display(diff);
setTimeout(timer, 1000);
}
}());
}
// wait for the page to load.
window.onload = function() {
var element = document.querySelector('#time'),
now = Date.now() / 1000,
// some random time within the next minute
futureTimeStamp = Math.floor(now + (Math.random() * 60));
// format the display however you wish.
function display(diff) {
var minutes = (diff / 60) | 0,
seconds = (diff % 60) | 0;
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
element.innerHTML = minutes + ":" + seconds;
}
startTimer(futureTimeStamp, display);
};
<span id="time"></span>
Also Math.round(new Date().getTime()/1000.0); will give you the number of seconds since the epoch, however it may be a little disingenuous to round the number. I think you would be better served by taking the floor:
var timestamp = Math.floor(Date.now() / 1000)); is probably a better option.
In addition I am not sure why you need the start time, current time and end time. In order to find the remaining number of second you just need to know when the timer should end and the current time.
I started working on a timer to show how long people have been on my page. The problem is that instead of counting the seconds, it just keeps adding zeros to the end. Can anyone show me where I went wrong?
<script language="javascript">
<!--
var seconds = 0
var minutes = 0
document.getElementById('timer').innerHTML = '0'
function Timer() {
if ( seconds < 10 ) {
seconds = "0" + seconds
}
else if ( minutes < 10 ) {
minutes = "0" + minutes
}
else if ( seconds >= 59 ){
seconds = 0
minutes += 1
}
else
seconds += 1
document.getElementById('timer').innerHTML = "You've been on my blog for "+minutes+" : "+seconds+" minutes."
setTimeout("Timer()",1000)
}
//-->
</script>
Well yes, because you're concatenating a string. The + operator does both concatenation and addition.
"0" + foo // concatenate the string "0" and foo
0 + foo // add foo to 0 (given that both are numbers)
You're going about the timer the wrong way though. Your script is not guaranteed to execute on time, any slight delay in execution will give you accumulative the wrong value. The right way to do a timer is to take a fixed start time and use that as the base to calculate the difference every second or so.
var start = Date.now();
function timer() {
alert(((Date.now() - start) / 1000) + ' seconds elapsed');
}
setInterval(timer, 1000);
You're switching the variable type for seconds from being:
var seconds = 0 // integer type
....
seconds = "0" + seconds // now seconds is holding a string!
seconds (and minutes) should only be integers.
Also, just focus on the seconds. Later, divide it by 60 to display number of minutes. seconds % 60 will be the remaining number of sec.