-1

I'm trying to make an infinitely looping countdown timer in JavaScript. I'm able to get the countdowns functioning as intended, but can't get them to reset properly once they hit 0/go below 0.

I should have specified, I apologize, for the first timer "mcReset" I need to reset the date to 7 days from the originally specified date when the timer hits 0.

For the second timer "onyReset" I need to reset the date to 5 days from the originally specified date when the timer hits 0.

So for example mcReset (Oct 14 9:28:00) would become Oct 21 9:28:00 and onyReset (Oct 17, 2019 12:00:00) would become Oct 22, 2019 12:00:00 and the countdown would infinitely loop from that.

I'm not super familiar with JavaScript so any help is appreciated :)

Here's the code:

// Set the date we're counting down to
var mcReset = new Date("Oct 14, 2019 9:28:00").getTime();
var onyReset = new Date("Oct  17, 2019 12:00:00").getTime();

// Update the count down every 1 second
var x = setInterval(function() {

  // Get today's date and time
  var now = new Date().getTime();
    
  // Find the distance between now and the count down date
  var distance = mcReset - now;
  var onyDistance = onyReset - now;
    
  // Time calculations for days, hours, minutes and seconds
  var mcDays = Math.floor(distance / (1000 * 60 * 60 * 24));
  var onyDays = Math.floor(onyDistance / (1000 * 60 * 60 * 24));
  var mcHours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
  var onyHours = Math.floor((onyDistance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
  var mcMinutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
  var onyMinutes = Math.floor((onyDistance % (1000 * 60 * 60)) / (1000 * 60));
  var mcSeconds = Math.floor((distance % (1000 * 60)) / 1000);
  var onySeconds = Math.floor((onyDistance % (1000 * 60)) / 1000);
    
  // Output the result in an element with id="demo"
  document.getElementById("demo").innerHTML = mcDays + "d " + mcHours + "h "
  + mcMinutes + "m " + mcSeconds + "s ";
  document.getElementById("ony").innerHTML = onyDays + "d " + onyHours + "h "
  + onyMinutes + "m " + onySeconds + "s ";
    
  // If the count down is over, reset
  if (distance < 0) {
   // do something here?
 // not sure what
  }
}, 1000);
p {
  text-align: center;
  font-size: 60px;
  margin-top: 0px;
}
<!DOCTYPE HTML>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>

<p id="demo"></p>
<p id="ony"></p>

</body>
</html>
MauriceNino
  • 6,214
  • 1
  • 23
  • 60
Bob G
  • 13
  • 1
  • 6
  • So what is your problem? reset it to what? The value or not to run the interval any more? – epascarello Oct 14 '19 at 13:37
  • You need to call `clearInterval(handle);` in your case: `clearInterval(x);` – MauriceNino Oct 14 '19 at 13:37
  • What you want to if less than 0 – Rahul Rana Oct 14 '19 at 13:37
  • @epascarello I added more information to the main post regarding what I need it to reset to. The value needs to reset, the interval can keep going, I want the "mcReset" and "onyReset" values to reset to a new date and then countdown to that date – Bob G Oct 14 '19 at 13:41
  • Do check this once https://momentjs.com – Arti Singh Oct 14 '19 at 13:43
  • Can you fix the code (and ideally implement a proper snippet using the `<>` button) so we can see what the code currently does? Also, are you asking how to add x days to a `Date()`? –  Oct 14 '19 at 13:47
  • Here's my take: https://jsfiddle.net/khrismuc/nreL5jx9/ –  Oct 14 '19 at 14:13
  • @ChrisG Can you please create an answer? I have found your solution to be the best for my use case – Bob G Oct 14 '19 at 14:32

3 Answers3

1

The key is to make sure each countdown has the proper target timestamp right inside the interval function that updates the page. If the countdown date is already in the past, add the countdown interval; that way the remaining time will jump seamlessly to counting down to the next timestamp.

Here's one way to do this:

const DAYS = 24 * 3600 * 1000;

const countdowns = [{
    id: "mcReset",
    timestamp: new Date("Oct 14, 2019 9:28:00").getTime(),
    interval: 7 * DAYS
  },
  {
    id: "onyReset",
    timestamp: new Date("Oct  17, 2019 12:00:00").getTime(),
    interval: 5 * DAYS
  },
  {
    id: "demo",
    timestamp: new Date(new Date().getTime() + 5000).getTime(),
    interval: 5000
  }
];

setInterval(() => {
  const now = new Date().getTime();
  countdowns.forEach(c => {
    while (c.timestamp < now) c.timestamp += c.interval; // set target to future date
    const tSecs = Math.floor((c.timestamp - now) / 1000);
    const secs = tSecs % 60;
    const tMins = (tSecs - secs) / 60;
    const mins = tMins % 60;
    const tHours = (tMins - mins) / 60;
    const hours = tHours % 24;
    const days = (tHours - hours) / 24;
    document.getElementById(c.id).textContent = `${days}d ${hours}h ${mins}m ${secs}s`;
  });
}, 1000);
p {
  text-align: center;
  font-size: 200%;
  margin-top: 0px;
}
<p id="mcReset"></p>
<p id="onyReset"></p>
<p id="demo"></p>
  • Thank you!! Works perfectly. If I wanted to display the date itself (10/17/2019, etc.) in another

    element, what would be the easiest way to do such a thing? And does this account for each individual user's timezone, or is there a way to standardize it to a specific timezone?

    – Bob G Oct 14 '19 at 14:42
  • @BobG All times use the browser's local timezone. So for me, this will count down to 9:28 GMT+1, regardless of the actual point in time. You can use `new Date("2019-10-14T09:28:00.1000Z")` to state a point in Zulu time, i.e. GMT+0. For instance if you're at GMT-5, you can plug in `04` instead of `09` and the count down will work anywhere. As for displaying a date: https://stackoverflow.com/questions/3552461/how-to-format-a-javascript-date –  Oct 14 '19 at 14:48
0

I have refactored your code a bit.

Here is a function that counts down to a specific date, and when done, it deletes that countdown and calls itself again with a new date:

// Helper function to get the current date and add 10 seconds on top of it
const get10SecsInFuture = () => {
  // Set the date we're counting down to
  let d = new Date();

  // Add one minute to date
  d.setTime(d.getTime() + 1000 * 10);
  
  return d;
}

// Make countDown a function
const countDown = (onyReset) => {
  let countDownHandle = setInterval(() => {

    // Get today's date and time
    let now = new Date().getTime();

    // Find the distance between now and the count down date
    let onyDistance = onyReset - now;

    // Time calculations for days, hours, minutes and seconds
    let onyDays = Math.floor(onyDistance / (1000 * 60 * 60 * 24));
    let onyHours = Math.floor((onyDistance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
    let onyMinutes = Math.floor((onyDistance % (1000 * 60 * 60)) / (1000 * 60));
    let onySeconds = Math.floor((onyDistance % (1000 * 60)) / 1000);

    // Output the result in an element with id="demo"
    document.getElementById("ony").innerHTML = onyDays + "d " + onyHours + "h "
    + onyMinutes + "m " + onySeconds + "s ";

    // If the count down is over, reset
    if (onyDistance <= 0) {
      clearInterval(countDownHandle);
      countDown(get10SecsInFuture());
    }
  }, 300);
}

countDown(get10SecsInFuture());
p {
  text-align: center;
  font-size: 60px;
  margin-top: 0px;
}
<!DOCTYPE HTML>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>

<p id="ony"></p>

</body>
</html>
MauriceNino
  • 6,214
  • 1
  • 23
  • 60
0

So add the number of days to the string and update the global variables with the new values.

function addDaysGetTime(date, numOfDays) {
  var date = new Date(date);
  date.setDate(date.getDate() + numOfDays);
  return date.getTime()
}

var mcReset = new Date("Oct 14, 2019 9:28:00").getTime();
var onyReset = new Date("Oct  17, 2019 12:00:00").getTime();
console.log("before", mcReset, onyReset)


// if( distance < 0) {
  mcReset = addDaysGetTime(mcReset, 7)
  onyReset = addDaysGetTime(onyReset, 5)
// }

   console.log("after", mcReset, onyReset)

technically you do not even need to use date methods. You just need to add milliseconds to the numbers.

// if( distance < 0) {
  mcReset += 604800000
  onyReset += 432000000
// }
epascarello
  • 204,599
  • 20
  • 195
  • 236