316

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.

Christopher Oezbek
  • 23,994
  • 6
  • 61
  • 85
Bartek
  • 3,203
  • 3
  • 12
  • 5
  • 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. – David Thomas Dec 16 '13 at 18:43
  • 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. – bjb568 Dec 16 '13 at 18:44
  • 2
    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 logic – Carlos Rafael Ramirez Apr 07 '15 at 02:48
  • 2
    I found these solutions to be simpler: http://stackoverflow.com/questions/32141035/countdown-timer-using-moment-js-mmss-format – nu everest Aug 25 '16 at 21:11
  • Look this: https://www.sitepoint.com/build-javascript-countdown-timer-no-dependencies/ – Erich García Jan 16 '17 at 20:01

3 Answers3

664

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

jlo
  • 2,157
  • 2
  • 17
  • 23
robbmj
  • 16,085
  • 8
  • 38
  • 63
  • 3
    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"? – Bartek Dec 16 '13 at 19:36
  • 2
    `minutes = minutes < 10 ? "0" + minutes : minutes;` – robbmj Dec 16 '13 at 19:37
  • 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? – timbram Jun 29 '15 at 04:45
  • @timbram `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. – robbmj Jul 01 '15 at 15:06
  • 14
    @timbram 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. – abustamam Jul 15 '15 at 22:06
  • 1
    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! – Savvas Parastatidis Apr 12 '16 at 10:28
  • 1
    How to call a functions once the timer become 00:00??? – Sangamesh Davey Jun 16 '16 at 11:22
  • 1
    is there any way to stop the js demo from resetting once it reaches 0 ? – Santosh Pillai Jul 15 '16 at 09:00
  • 1
    stopped it from resetting by if (--timer < 0) { timer = 0; } – Santosh Pillai Jul 15 '16 at 09:10
  • 4
    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. – Dzung Nguyen Aug 18 '16 at 22:58
  • `(diff / 60) | 0;` - what is `|` here? How is it called? – Edgar Sep 15 '16 at 14:19
  • I found this answer: http://stackoverflow.com/questions/7487977/using-bitwise-or-0-to-floor-a-number . What I was looking for. – Edgar Sep 15 '16 at 14:26
  • @Edgar yep that's what it does. – robbmj Sep 15 '16 at 14:32
  • @robbmj Hey - great post. Thanks - Did you ever implement the pause feature? Could really use that in one of the projects im working on. – Ricky Mason Feb 24 '17 at 19:22
  • In what way is the second version "more accurate"? – BornToCode Sep 01 '17 at 09:04
  • 1
    @BornToCode 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. – robbmj Sep 01 '17 at 12:58
  • anyone know hwo to add ike 2 more minutes after it stops at 0? – shikiko Jan 12 '18 at 01:52
  • 1
    @robbmj 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 ... etc – Mike Pala Jan 26 '18 at 16:41
  • Answer is flawed because of the use of setTimeout/Interval since it does not fire accurately. – epascarello Feb 09 '18 at 15:48
  • @epascarello please see last section for a more accurate timer that deals with the inaccuracy of `setTimeout` and `setInterval`. – robbmj Feb 09 '18 at 22:19
  • there is a bug in the jquery code: displayId.text(minutes + ":" + seconds); The right way is: displayId.html(minutes + ":" + seconds); – Zoltán Süle Aug 01 '18 at 12:51
  • @ZoltánSüle I should probably update the answer so that the normal JS uses innerHTML as well. – robbmj Aug 01 '18 at 13:01
  • @robbmj I was wrong. In this case there is no real difference between the text() and the html() functions – Zoltán Süle Aug 01 '18 at 13:14
  • @ZoltánSüle no worries, better to point something out and be wrong then let a potential bug slip through. – robbmj Aug 01 '18 at 21:12
  • How stop timer after a button clicked...and then start it again after another click? – Mostafa Oct 14 '18 at 04:43
  • 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); – Melu Feb 15 '19 at 20:18
  • 1
    How would you go about making the simple example also display hours? – V1xIII May 13 '20 at 20:54
  • 1
    @V1xIII This should do what you want: https://jsfiddle.net/ejdcwmuy/ – robbmj May 19 '20 at 12:30
  • though it doesn't look `simplest` to me – Shiz Aug 25 '20 at 06:10
  • If I want to include Hours, so have as output to display a common Hrs:Mins:Sec output, how would I change this code – LeCoda May 18 '21 at 12:26
  • is there any way to restart the timer? i tried but it just launches several timers at the same time – Pedro Joaquín Jul 29 '21 at 18:02
  • In case people are still looking for start/stop button modified versions, here they are: Vanilla js https://jsfiddle.net/u7ahcdgn/2/ jQuery https://jsfiddle.net/qe15zdwb/1/ More accurate https://jsfiddle.net/qe15zdwb/2/ And the one I ended up using: https://jsfiddle.net/6Luaq138/ I honestly don't know how to implement a Pause/Resume button, if you do please post/comment it below – jlo Apr 24 '23 at 12:45
38

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>!
isherwood
  • 58,414
  • 16
  • 114
  • 157
Durai
  • 542
  • 3
  • 4
  • 4
    Does not accurately represent each second, it's counting down much too fast. – Scott Rowley Nov 21 '17 at 19:15
  • 4
    Changing the 500 to 1000 seems to make it accurate. – Scott Rowley Nov 21 '17 at 19:16
  • Slick solution, hour should be changed to minute though to avoid confusion – embulldogs99 May 26 '20 at 21:38
  • 1
    Seems like `5:60` should never be a thing. – isherwood Dec 20 '22 at 20:24
  • 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. – Ultimater Dec 21 '22 at 09:47
31

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

Coding Enthusiast
  • 3,865
  • 1
  • 27
  • 50
cocco
  • 16,442
  • 7
  • 62
  • 77