Who Me Dunno Mate
Who Me Dunno Mate

Reputation: 540

Minutes not quite in sync with seconds

I have a timer which I am testing, it seems there is a bit of drift between when the minute countdown goes down by 1 and seconds whenever it reaches 59 seconds ()ie every minute:-

How can I alter this so they are both in sync?

my code is the following:-

$(document).ready(function() {
  function now() {
    return window.performance ? window.performance.now() : Date.now();
  }

  function tick() {
    var timeRemaining = countdown - ((now() - initTick) / 1000);
    timeRemaining = timeRemaining >= 0 ? timeRemaining : 0;

    var countdownMinutes = Math.floor(timeRemaining / 60);
    var countdownSeconds = timeRemaining.toFixed() % 60;

    countdownTimer.innerHTML = countdownMinutes + ":" + countdownSeconds;

    if (countdownSeconds < 10) {
      countdownTimer.innerHTML = countdownMinutes + ":" + 0 + countdownSeconds;
    }

    if (timeRemaining > 0) {
      setTimeout(tick, delay);
    }
  }

  var countdown = 600; // time in seconds until user may login again
  var delay = 20; // time (in ms) per tick
  var initTick = now(); // timestamp (in ms) when script is initialized
  var countdownTimer = document.querySelector(".timer"); // element to have countdown written to
  setTimeout(tick, delay);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div class="timer"></div>

js fiddle: https://jsfiddle.net/robbiemcmullen/cer8qemt/1/

Upvotes: 0

Views: 47

Answers (2)

Alex83690
Alex83690

Reputation: 817

Here is a version using setInterval and removing the use of .toFixed () Why do you use an interval of 20ms and not 1 second?

//method for countdown timer
$(document).ready(function() {

		function now() {
		    return window.performance ? window.performance.now() : Date.now();
		}

		function tick() {
      var timeRemaining = countdown - elapsedTime;
      var countdownMinutes = Math.floor(timeRemaining / 60);
      var countdownSeconds = timeRemaining % 60;

      countdownTimer.innerHTML = countdownMinutes + ":" + countdownSeconds;

      if (countdownSeconds < 10) {
        countdownTimer.innerHTML = countdownMinutes + ":" + 0 + countdownSeconds;
      }
      ++elapsedTime;

      return timeRemaining;
		}

      var countdown = 600;
      var elapsedTime = 0;
      var timeRemaining;
      // countdown: time in seconds until user may login again
      //var delay = 20;
      // delay: time (in ms) per tick
      var initTick = now(); // initTick: timestamp (in ms) when script is initialized
      var countdownTimer = document.querySelector(".timer");
      // countdownTimer: element to have countdown written to
      var interval = setInterval(function() {
        if(tick() <= 0) {
          clearInterval(interval);
        }
      }, 1000);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="timer"></div>

js fiddle https://jsfiddle.net/ud3wm8t1/

Upvotes: 0

fdomn-m
fdomn-m

Reputation: 28611

The issue is the precision is not the same for minutes and seconds.

You need to round to the nearest second before /60 / %60.

Consider: exactly 9 mins remaining:

var x = 540; 
console.log(x.toFixed() % 60, Math.floor(x / 60));` 

Output is: (0,9)

Then consider the call 20 ms later:

var x = 539.980; 
console.log(x.toFixed() % 60, Math.floor(x / 60));

the output is now: (0, 8).

So the seconds haven't changed (yet) but the minute does.

Upvotes: 2

Related Questions