How to write a countdown timer in JavaScript? [closed]
Asked Answered
S

3

318

Just wanted to ask how to create the simplest possible countdown timer.

There'll be a sentence on the site saying:

"Registration closes in 05:00 minutes!"

So, what I want to do is to create a simple js countdown timer that goes from "05:00" to "00:00" and then resets to "05:00" once it ends.

I was going through some answers before, but they all seem too intense (Date objects, etc.) for what I want to do.

Seafood answered 16/12, 2013 at 18:41 Comment(5)
And again, you're leaving out the relevant HTML, though at least you've sort of explained the complexity issue this time. But seriously, you need to look into making a solution yourself, and then come and ask us about problems you're having.Conception
Code examples with complaints on how they are too complicated? Anyway, I think you could easily setInterval and make it .innerHTML based, instead of date based.Innovate
Yes, people should look for making the solution themselves. But with javaScript there are plenty examples of doing common tasks. I know how to do a count down timer, but I prefer if I find one in the web (like a component). So thanks to this question and the extensive answer I found what I was looking for. Countdown logicTalmudist
I found these solutions to be simpler: #32141535Microelement
Look this: sitepoint.com/build-javascript-countdown-timer-no-dependenciesElijaheliminate
V
679

I have two demos, one with jQuery and one without. Neither use date functions and are about as simple as it gets.

Demo with vanilla JavaScript (version with a start/stop button here)

function startTimer(duration, display) {
    var timer = duration, minutes, seconds;
    setInterval(function () {
        minutes = parseInt(timer / 60, 10);
        seconds = parseInt(timer % 60, 10);

        minutes = minutes < 10 ? "0" + minutes : minutes;
        seconds = seconds < 10 ? "0" + seconds : seconds;

        display.textContent = minutes + ":" + seconds;

        if (--timer < 0) {
            timer = duration;
        }
    }, 1000);
}

window.onload = function () {
    var fiveMinutes = 60 * 5,
        display = document.querySelector('#time');
    startTimer(fiveMinutes, display);
};
<body>
    <div>Registration closes in <span id="time">05:00</span> minutes!</div>
</body>

Demo with jQuery (version with a start/stop button here)

function startTimer(duration, display) {
    var timer = duration, minutes, seconds;
    setInterval(function () {
        minutes = parseInt(timer / 60, 10);
        seconds = parseInt(timer % 60, 10);

        minutes = minutes < 10 ? "0" + minutes : minutes;
        seconds = seconds < 10 ? "0" + seconds : seconds;

        display.text(minutes + ":" + seconds);

        if (--timer < 0) {
            timer = duration;
        }
    }, 1000);
}

jQuery(function ($) {
    var fiveMinutes = 60 * 5,
        display = $('#time');
    startTimer(fiveMinutes, display);
});

However if you want a more accurate timer that is only slightly more complicated: (version with a start/stop button here)

function startTimer(duration, display) {
    var start = Date.now(),
        diff,
        minutes,
        seconds;
    function timer() {
        // get the number of seconds that have elapsed since 
        // startTimer() was called
        diff = duration - (((Date.now() - start) / 1000) | 0);

        // does the same job as parseInt truncates the float
        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) {
            // add one second so that the count down starts at the full duration
            // example 05:00 not 04:59
            start = Date.now() + 1000;
        }
    };
    // we don't want to wait a full second before the timer starts
    timer();
    setInterval(timer, 1000);
}

window.onload = function () {
    var fiveMinutes = 60 * 5,
        display = document.querySelector('#time');
    startTimer(fiveMinutes, display);
};
<body>
    <div>Registration closes in <span id="time"></span> minutes!</div>
</body>

Now that we have made a few pretty simple timers we can start to think about re-usability and separating concerns. We can do this by asking "what should a count down timer do?"

  • Should a count down timer count down? Yes
  • Should a count down timer know how to display itself on the DOM? No
  • Should a count down timer know to restart itself when it reaches 0? No
  • Should a count down timer provide a way for a client to access how much time is left? Yes

So with these things in mind lets write a better (but still very simple) CountDownTimer

function CountDownTimer(duration, granularity) {
  this.duration = duration;
  this.granularity = granularity || 1000;
  this.tickFtns = [];
  this.running = false;
}

CountDownTimer.prototype.start = function() {
  if (this.running) {
    return;
  }
  this.running = true;
  var start = Date.now(),
      that = this,
      diff, obj;

  (function timer() {
    diff = that.duration - (((Date.now() - start) / 1000) | 0);
        
    if (diff > 0) {
      setTimeout(timer, that.granularity);
    } else {
      diff = 0;
      that.running = false;
    }

    obj = CountDownTimer.parse(diff);
    that.tickFtns.forEach(function(ftn) {
      ftn.call(this, obj.minutes, obj.seconds);
    }, that);
  }());
};

CountDownTimer.prototype.onTick = function(ftn) {
  if (typeof ftn === 'function') {
    this.tickFtns.push(ftn);
  }
  return this;
};

CountDownTimer.prototype.expired = function() {
  return !this.running;
};

CountDownTimer.parse = function(seconds) {
  return {
    'minutes': (seconds / 60) | 0,
    'seconds': (seconds % 60) | 0
  };
};

So why is this implementation better than the others? Here are some examples of what you can do with it. Note that all but the first example can't be achieved by the startTimer functions.

An example that displays the time in XX:XX format and restarts after reaching 00:00

An example that displays the time in two different formats

An example that has two different timers and only one restarts

An example that starts the count down timer when a button is pressed

Vincents answered 16/12, 2013 at 18:50 Comment(32)
You're the man! That's exactly what I was looking for. Thank you! One more thing: how can I add "0" in front of minutes, so it shows "04:59", instead of "4:59"?Seafood
minutes = minutes < 10 ? "0" + minutes : minutes;Vincents
In the very first demo, with Vanilla JavaScript, what kind of variable is timer? I have never seen anything like that! And how can you set it when minutes and seconds are not yet defined?Nephritic
@Nephritic timer, initially is just a copy of the paramater duration and it is just a number. The reason why it is needed is to keep track of the remaining time, that can't be done with the duration parameter as the timer needs to be reset when it reaches 0. minutes and seconds are calculated based on the value of timer. Hope this helps.Vincents
@Nephritic it looked weird to me at first too, until i realized that a comma after a var declaration separates different declarations. so minutes and seconds are simply declared (but un-initialized) variables. so timer is simply just equal the the duration parameter, nothing more, nothing less.Ghana
Is there a way to find the current value of the timer or how much time has passed since its start? I could parse the html value but it's a bit silly when the real value is there!Unrefined
How to call a functions once the timer become 00:00???Swor
is there any way to stop the js demo from resetting once it reaches 0 ?Lamellibranch
stopped it from resetting by if (--timer < 0) { timer = 0; }Lamellibranch
How do you add a reset options? And also a pause and resume? I tried adding a field this.reset, and check that in the closure. But the clock keeps going though.Swithbart
(diff / 60) | 0; - what is | here? How is it called?Berlioz
I found this answer: #7488477 . What I was looking for.Berlioz
@Berlioz yep that's what it does.Vincents
@Vincents Hey - great post. Thanks - Did you ever implement the pause feature? Could really use that in one of the projects im working on.Kalimantan
In what way is the second version "more accurate"?Futtock
@Futtock Using a Date object to calculate exactly how much time is remaining or has elapsed is needed as setInterval and setTimeout can't guarantee that they will be called in exactly n milliseconds.Vincents
anyone know hwo to add ike 2 more minutes after it stops at 0?Cassirer
@Vincents I really like your solution... the first one, the vanilla one :) if you have a moment could you please show me how you would add a reset button to that solution. I mean a button that would NOT stop the timer... just reset it back to 5:00 ... so it would automatically go to 4:59... 4:58 ... etcTranslative
Answer is flawed because of the use of setTimeout/Interval since it does not fire accurately.Nickelson
@Nickelson please see last section for a more accurate timer that deals with the inaccuracy of setTimeout and setInterval.Vincents
there is a bug in the jquery code: displayId.text(minutes + ":" + seconds); The right way is: displayId.html(minutes + ":" + seconds);Newcomer
@ZoltánSüle I should probably update the answer so that the normal JS uses innerHTML as well.Vincents
@Vincents I was wrong. In this case there is no real difference between the text() and the html() functionsNewcomer
@ZoltánSüle no worries, better to point something out and be wrong then let a potential bug slip through.Vincents
How stop timer after a button clicked...and then start it again after another click?Progressist
excellent timer, one suggestion is to do something like var objMyInterval = setInterval(function timer() {... now to stop timer after minutes <= 0 & seconds <=0 just call clearInterval(objMyInterval);Peterpeterborough
How would you go about making the simple example also display hours?Koal
@Koal This should do what you want: jsfiddle.net/ejdcwmuyVincents
though it doesn't look simplest to meOvertake
If I want to include Hours, so have as output to display a common Hrs:Mins:Sec output, how would I change this codeRoband
is there any way to restart the timer? i tried but it just launches several timers at the same timeResection
In case people are still looking for start/stop button modified versions, here they are: Vanilla js jsfiddle.net/u7ahcdgn/2 jQuery jsfiddle.net/qe15zdwb/1 More accurate jsfiddle.net/qe15zdwb/2 And the one I ended up using: jsfiddle.net/6Luaq138 I honestly don't know how to implement a Pause/Resume button, if you do please post/comment it belowLanglauf
R
39

You can easily create a timer functionality by using setInterval.Below is the code which you can use it to create the timer.

http://jsfiddle.net/ayyadurai/GXzhZ/1/

window.onload = function() {
  var minute = 5;
  var sec = 60;
  setInterval(function() {
    document.getElementById("timer").innerHTML = minute + ":" + sec;
    sec--;

    if (sec == 00) {
      minute--;
      sec = 60;

      if (minute == 0) {
        minute = 5;
      }
    }
  }, 1000);
}
Registration closes in <span id="timer">5:00</span>!
Rasia answered 16/12, 2013 at 18:44 Comment(6)
Does not accurately represent each second, it's counting down much too fast.Assurgent
Changing the 500 to 1000 seems to make it accurate.Assurgent
Slick solution, hour should be changed to minute though to avoid confusionCottontail
Seems like 5:60 should never be a thing.Emmery
Multiple issues: 1) this is supposed to be a 5 minute timer, not a 5 minute and 60 second timer. 2) Why is sec being set to 60? 5:60 isn't valid for timers. This would mean 6 minutes but treated as 5 minutes by this code. 3) The timer never shows 5:00 but instead shows 4:60, etc. 4) When the timer gets to 0 minutes and 60 seconds, the timer starts over again when there's still a minute left according to the display. 5) When the timer's seconds goes into single digits, it's not using a leading zero. 6) Also have to wait a full second before the 1 second interval kicks in.Swartz
This API does not guarantee that timers will run exactly on schedule. Delays due to CPU load, other tasks, etc, are to be expected. html.spec.whatwg.org/multipage/… You should fetch the initial timestamp and subtract current timestamp from it on each function call.Hanford
R
32

If you want a real timer you need to use the date object.

Calculate the difference.

Format your string.

window.onload=function(){
      var start=Date.now(),r=document.getElementById('r');
      (function f(){
      var diff=Date.now()-start,ns=(((3e5-diff)/1e3)>>0),m=(ns/60)>>0,s=ns-m*60;
      r.textContent="Registration closes in "+m+':'+((''+s).length>1?'':'0')+s;
      if(diff>3e5){
         start=Date.now()
      }
      setTimeout(f,1e3);
      })();
}

Example

Jsfiddle

not so precise timer

var time=5*60,r=document.getElementById('r'),tmp=time;

setInterval(function(){
    var c=tmp--,m=(c/60)>>0,s=(c-m*60)+'';
    r.textContent='Registration closes in '+m+':'+(s.length>1?'':'0')+s
    tmp!=0||(tmp=time);
},1000);

JsFiddle

Rasping answered 16/12, 2013 at 18:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.