153

I want to use a simple countdown timer starting at 30 seconds from when the function is run and ending at 0. No milliseconds. How can it be coded?

Barlas Apaydin
  • 7,233
  • 11
  • 55
  • 86
Michael Swarts
  • 3,813
  • 8
  • 31
  • 41

13 Answers13

259
var count=30;

var counter=setInterval(timer, 1000); //1000 will  run it every 1 second

function timer()
{
  count=count-1;
  if (count <= 0)
  {
     clearInterval(counter);
     //counter ended, do something here
     return;
  }

  //Do code for showing the number of seconds here
}

To make the code for the timer appear in a paragraph (or anywhere else on the page), just put the line:

<span id="timer"></span>

where you want the seconds to appear. Then insert the following line in your timer() function, so it looks like this:

function timer()
{
  count=count-1;
  if (count <= 0)
  {
     clearInterval(counter);
     return;
  }

 document.getElementById("timer").innerHTML=count + " secs"; // watch for spelling
}
Community
  • 1
  • 1
Ali
  • 261,656
  • 265
  • 575
  • 769
  • Thanks for the answer. I am having difficulty using it because my timer appears in a paragraph. How can I put the 30, 29, 28, etc. in the middle of a paragraph? – Michael Swarts Jul 28 '09 at 05:58
  • 1
    I edited my answer to show you how to display the timer in the paragraph :) – Ali Jul 28 '09 at 13:17
  • 2
    In the middle of a paragraph (horizontally) :

    – Alsciende Jul 28 '09 at 13:19
  • Click, your timer will only display "0 secs". You should put the innerHTML update after the decrementation, not in the end case. – Alsciende Jul 28 '09 at 13:24
  • Whereever you want the timer to begin, just put in the code `timer();` to call the timer function – Ali Aug 15 '09 at 09:44
  • 1
    Hi how can I stop the timer running on page load and instead only when a button is pressed? Also how can I make it reset the timer when a button is pressed after the timer has already ran down? – crmepham Mar 17 '13 at 12:29
  • From: http://www.w3schools.com/jsref/met_win_clearinterval.asp "**Note: To be able to use the clearInterval() method, you must use a global variable when creating the interval method**" – Yasen Ivanov Jan 26 '16 at 11:00
  • @Alsciende Make it more visible :

    – aswzen Feb 27 '18 at 05:02
106

I wrote this script some time ago:

Usage:

var myCounter = new Countdown({  
    seconds:5,  // number of seconds to count down
    onUpdateStatus: function(sec){console.log(sec);}, // callback for each second
    onCounterEnd: function(){ alert('counter ended!');} // final action
});

myCounter.start();

function Countdown(options) {
  var timer,
  instance = this,
  seconds = options.seconds || 10,
  updateStatus = options.onUpdateStatus || function () {},
  counterEnd = options.onCounterEnd || function () {};

  function decrementCounter() {
    updateStatus(seconds);
    if (seconds === 0) {
      counterEnd();
      instance.stop();
    }
    seconds--;
  }

  this.start = function () {
    clearInterval(timer);
    timer = 0;
    seconds = options.seconds;
    timer = setInterval(decrementCounter, 1000);
  };

  this.stop = function () {
    clearInterval(timer);
  };
}
Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
59

So far the answers seem to rely on code being run instantly. If you set a timer for 1000ms, it will actually be around 1008 instead.

Here is how you should do it:

function timer(time,update,complete) {
    var start = new Date().getTime();
    var interval = setInterval(function() {
        var now = time-(new Date().getTime()-start);
        if( now <= 0) {
            clearInterval(interval);
            complete();
        }
        else update(Math.floor(now/1000));
    },100); // the smaller this number, the more accurate the timer will be
}

To use, call:

timer(
    5000, // milliseconds
    function(timeleft) { // called every step to update the visible countdown
        document.getElementById('timer').innerHTML = timeleft+" second(s)";
    },
    function() { // what to do after
        alert("Timer complete!");
    }
);
Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • 2
    Spot on, as you said that's the one and only way to do it right! – mcella Oct 23 '14 at 14:42
  • 4
    I gave it a thumbs up, with one caveat - _for display purposes_ you probably want to show the ceiling (Math.ceil()) instead of the floor. It's really disorienting when the clock reaches 0 a second before the alert fires. (Then of course there needs to be an additional call to update() before complete()) – Paul Williams Apr 27 '15 at 04:33
21

Here is another one if anyone needs one for minutes and seconds:

    var mins = 10;  //Set the number of minutes you need
    var secs = mins * 60;
    var currentSeconds = 0;
    var currentMinutes = 0;
    /* 
     * The following line has been commented out due to a suggestion left in the comments. The line below it has not been tested. 
     * setTimeout('Decrement()',1000);
     */
    setTimeout(Decrement,1000); 

    function Decrement() {
        currentMinutes = Math.floor(secs / 60);
        currentSeconds = secs % 60;
        if(currentSeconds <= 9) currentSeconds = "0" + currentSeconds;
        secs--;
        document.getElementById("timerText").innerHTML = currentMinutes + ":" + currentSeconds; //Set the element id you need the time put into.
        if(secs !== -1) setTimeout('Decrement()',1000);
    }
Layton Everson
  • 1,148
  • 9
  • 18
  • You shouldn't pass a string to the first parameter of setTimeout, `setTimeout(Decrement, 1000)` is preferred. http://stackoverflow.com/questions/6232574/is-it-bad-practice-to-pass-a-string-to-settimeout-if-yes-why – Scottux Apr 01 '15 at 17:24
  • Thank you for the suggestion, I have updated the script. – Layton Everson Jun 19 '15 at 06:35
3

// Javascript Countdown
// Version 1.01 6/7/07 (1/20/2000)
// by TDavid at http://www.tdscripts.com/
var now = new Date();
var theevent = new Date("Sep 29 2007 00:00:01");
var seconds = (theevent - now) / 1000;
var minutes = seconds / 60;
var hours = minutes / 60;
var days = hours / 24;
ID = window.setTimeout("update();", 1000);

function update() {
  now = new Date();
  seconds = (theevent - now) / 1000;
  seconds = Math.round(seconds);
  minutes = seconds / 60;
  minutes = Math.round(minutes);
  hours = minutes / 60;
  hours = Math.round(hours);
  days = hours / 24;
  days = Math.round(days);
  document.form1.days.value = days;
  document.form1.hours.value = hours;
  document.form1.minutes.value = minutes;
  document.form1.seconds.value = seconds;
  ID = window.setTimeout("update();", 1000);
}
<p><font face="Arial" size="3">Countdown To January 31, 2000, at 12:00: </font>
</p>
<form name="form1">
  <p>Days
    <input type="text" name="days" value="0" size="3">Hours
    <input type="text" name="hours" value="0" size="4">Minutes
    <input type="text" name="minutes" value="0" size="7">Seconds
    <input type="text" name="seconds" value="0" size="7">
  </p>
</form>
T J
  • 42,762
  • 13
  • 83
  • 138
Kedarnath
  • 169
  • 1
  • 2
  • 8
    This script uses very bad practices from the 90's. And also 1.5 hours is not 2 hours. It's 1 hour 30 min. You should use `Math.floor`, not `Math.round` – corbacho Feb 27 '13 at 15:01
3

Just modified @ClickUpvote's answer:

You can use IIFE (Immediately Invoked Function Expression) and recursion to make it a little bit more easier:

var i = 5;  //set the countdown
(function timer(){
    if (--i < 0) return;
    setTimeout(function(){
        console.log(i + ' secs');  //do stuff here
        timer();
    }, 1000);
})();

var i = 5;
(function timer(){
    if (--i < 0) return;
    setTimeout(function(){
        document.getElementsByTagName('h1')[0].innerHTML = i + ' secs';
        timer();
    }, 1000);
})();
<h1>5 secs</h1>
Rohit Sharma
  • 3,304
  • 2
  • 19
  • 34
2

Expanding upon the accepted answer, your machine going to sleep, etc. may delay the timer from working. You can get a true time, at the cost of a little processing. This will give a true time left.

<span id="timer"></span>

<script>
var now = new Date();
var timeup = now.setSeconds(now.getSeconds() + 30);
//var timeup = now.setHours(now.getHours() + 1);

var counter = setInterval(timer, 1000);

function timer() {
  now = new Date();
  count = Math.round((timeup - now)/1000);
  if (now > timeup) {
      window.location = "/logout"; //or somethin'
      clearInterval(counter);
      return;
  }
  var seconds = Math.floor((count%60));
  var minutes = Math.floor((count/60) % 60);
  document.getElementById("timer").innerHTML = minutes + ":" + seconds;
}
</script>
Patrick Knott
  • 1,666
  • 15
  • 15
1

For the sake of performances, we can now safely use requestAnimationFrame for fast looping, instead of setInterval/setTimeout.

When using setInterval/setTimeout, if a loop task is taking more time than the interval, the browser will simply extend the interval loop, to continue the full rendering. This is creating issues. After minutes of setInterval/setTimeout overload, this can freeze the tab, the browser or the whole computer.

Internet devices have a wide range of performances, so it's quite impossible to hardcode a fixed interval time in milliseconds!

Using the Date object, to compare the start Date Epoch and the current. This is way faster than everything else, the browser will take care of everything, at a steady 60FPS (1000 / 60 = 16.66ms by frame) -a quarter of an eye blink- and if the task in the loop is requiring more than that, the browser will drop some repaints.

This allow a margin before our eyes are noticing (Human = 24FPS => 1000 / 24 = 41.66ms by frame = fluid animation!)

https://caniuse.com/#search=requestAnimationFrame

/* Seconds to (STRING)HH:MM:SS.MS ------------------------*/
/* This time format is compatible with FFMPEG ------------*/
function secToTimer(sec){
  const o = new Date(0), p =  new Date(sec * 1000)
  return new Date(p.getTime()-o.getTime()).toString().split(" ")[4] + "." + p.getMilliseconds()
}

/* Countdown loop ----------------------------------------*/
let job, origin = new Date().getTime()
const timer = () => {
  job = requestAnimationFrame(timer)
  OUT.textContent = secToTimer((new Date().getTime() - origin) / 1000)
}

/* Start looping -----------------------------------------*/
requestAnimationFrame(timer)

/* Stop looping ------------------------------------------*/
// cancelAnimationFrame(job)

/* Reset the start date ----------------------------------*/
// origin = new Date().getTime()
span {font-size:4rem}
<span id="OUT"></span>
<br>
<button onclick="origin = new Date().getTime()">RESET</button>
<button onclick="requestAnimationFrame(timer)">RESTART</button>
<button onclick="cancelAnimationFrame(job)">STOP</button>
NVRM
  • 11,480
  • 1
  • 88
  • 87
0

You can do as follows with pure JS. You just need to provide the function with the number of seconds and it will do the rest.

var insertZero = n => n < 10 ? "0"+n : ""+n,
   displayTime = n => n ? time.textContent = insertZero(~~(n/3600)%3600) + ":" +
                                             insertZero(~~(n/60)%60) + ":" +
                                             insertZero(n%60)
                        : time.textContent = "IGNITION..!",
 countDownFrom = n => (displayTime(n), setTimeout(_ => n ? sid = countDownFrom(--n)
                                                         : displayTime(n), 1000)),
           sid;
countDownFrom(3610);
setTimeout(_ => clearTimeout(sid),20005);
<div id="time"></div>
Redu
  • 25,060
  • 6
  • 56
  • 76
0

Based on the solution presented by @Layton Everson I developed a counter including hours, minutes and seconds:

var initialSecs = 86400;
var currentSecs = initialSecs;

setTimeout(decrement,1000); 

function decrement() {
   var displayedSecs = currentSecs % 60;
   var displayedMin = Math.floor(currentSecs / 60) % 60;
   var displayedHrs = Math.floor(currentSecs / 60 /60);

    if(displayedMin <= 9) displayedMin = "0" + displayedMin;
    if(displayedSecs <= 9) displayedSecs = "0" + displayedSecs;
    currentSecs--;
    document.getElementById("timerText").innerHTML = displayedHrs + ":" + displayedMin + ":" + displayedSecs;
    if(currentSecs !== -1) setTimeout(decrement,1000);
}
Aiwatko
  • 385
  • 2
  • 6
  • 17
0

// Javascript Countdown
// Version 1.01 6/7/07 (1/20/2000)
// by TDavid at http://www.tdscripts.com/
var now = new Date();
var theevent = new Date("Nov 13 2017 22:05:01");
var seconds = (theevent - now) / 1000;
var minutes = seconds / 60;
var hours = minutes / 60;
var days = hours / 24;
ID = window.setTimeout("update();", 1000);

function update() {
  now = new Date();
  seconds = (theevent - now) / 1000;
  seconds = Math.round(seconds);
  minutes = seconds / 60;
  minutes = Math.round(minutes);
  hours = minutes / 60;
  hours = Math.round(hours);
  days = hours / 24;
  days = Math.round(days);
  document.form1.days.value = days;
  document.form1.hours.value = hours;
  document.form1.minutes.value = minutes;
  document.form1.seconds.value = seconds;
  ID = window.setTimeout("update();", 1000);
}
<p><font face="Arial" size="3">Countdown To January 31, 2000, at 12:00: </font>
</p>
<form name="form1">
  <p>Days
    <input type="text" name="days" value="0" size="3">Hours
    <input type="text" name="hours" value="0" size="4">Minutes
    <input type="text" name="minutes" value="0" size="7">Seconds
    <input type="text" name="seconds" value="0" size="7">
  </p>
</form>
maztt
  • 12,278
  • 21
  • 78
  • 153
0

My solution works with MySQL date time formats and provides a callback function. on complition. Disclaimer: works only with minutes and seconds, as this is what I needed.

jQuery.fn.countDownTimer = function(futureDate, callback){
    if(!futureDate){
        throw 'Invalid date!';
    }

    var currentTs = +new Date();
    var futureDateTs = +new Date(futureDate);

    if(futureDateTs <= currentTs){
        throw 'Invalid date!';
    }


    var diff = Math.round((futureDateTs - currentTs) / 1000);
    var that = this;

    (function countdownLoop(){
        // Get hours/minutes from timestamp
        var m = Math.floor(diff % 3600 / 60);
        var s = Math.floor(diff % 3600 % 60);
        var text = zeroPad(m, 2) + ':' + zeroPad(s, 2);

        $(that).text(text);

        if(diff <= 0){
            typeof callback === 'function' ? callback.call(that) : void(0);
            return;
        }

        diff--;
        setTimeout(countdownLoop, 1000);
    })();

    function zeroPad(num, places) {
      var zero = places - num.toString().length + 1;
      return Array(+(zero > 0 && zero)).join("0") + num;
    }
}

// $('.heading').countDownTimer('2018-04-02 16:00:59', function(){ // on complete})
nikksan
  • 3,341
  • 3
  • 22
  • 27
0
var hr = 0;
var min = 0;
var sec = 0;
var count = 0;
var flag = false;


function start(){
    flag = true;
    stopwatch();


}
function stop(){
    flag = false;

}

function reset(){
    flag = false;
    hr = 0;
    min = 0;
    sec = 0;
    count = 0;
    document.getElementById("hr").innerHTML = "00";
    document.getElementById("min").innerHTML = "00";
    document.getElementById("sec").innerHTML = "00";
    document.getElementById("count").innerHTML = "00";

}



function stopwatch(){
    if(flag == true){
        count = count + 1;
        setTimeout( 'stopwatch()', 10);

    if(count ==100){
        count =0;
        sec = sec +1;

    }
    }

    if(sec ==60){
        min = min +1 ;
        sec = 0;

    }
      if(min == 60){
        hr = hr +1 ;
        min = 0;
        sec = 0;

    }
    var hrs = hr;
    var mins = min;
    var secs = sec;
    if(hr<10){
        hrs ="0" + hr; 

    }
    if(min<10){
        mins ="0" + min; 

    }
   if(sec<10){
        secs ="0" + sec; 

    }
    document.getElementById("hr").innerHTML = hrs;
    document.getElementById("min").innerHTML = mins;
    document.getElementById("sec").innerHTML = secs;
    document.getElementById("count").innerHTML = count;
      
}