2

I have a timer to keep track of the time the user spends doing something. There's a button that, among other things, resets the timer to zero. That works fine.

However, when the user is away (i.e. taking their 15 or 30 minute breaks), the computer must be locked. I've noticed that the time is inconsistent upon return. Some times it appears the timer doesn't move until the user returns. Sometimes it's a few seconds, or a few minutes, but is never the time the user was way - always LESS.

For instance, if I lock the PC now, and the timer is on 5 minutes and 38 seconds, and I take a 15 minute break, I'll typically return to a timer that's roughly where it was when I left, or perhaps it'll be like 6 minutes and 5 seconds.

How can I fix this? Is there any way to ensure setInterval() continues to behave consistently, or am I better doing something else (such as comparing time stamps instead of an independent counter like I have now)?

For what it's worth, it seems even MORE inconsistent now that we are using VDI workstations, though I don't know if that makes a difference (the issue happened on normal workstations as well).

EDIT: I noticed in another question this appears to also be a thing with Chrome (maybe)? And how it throttles when not the active window or tab. Are there workarounds for --app-mode windows?

  • related? - https://stackoverflow.com/questions/5927284/how-can-i-make-setinterval-also-work-when-a-tab-is-inactive-in-chrome – James Jul 30 '21 at 21:06
  • Gonna assume this question might get the axe for now. I'm leaving work now but I'll check it Monday or from home. Thank you, and it might give me some insight as to what I can do, thank you! – Anthony LoPrimo Jul 30 '21 at 21:07
  • the duration indicated in the setInterval is purely informal, and can in no case be used for timing – Mister Jojo Jul 30 '21 at 21:13
  • So use the clock.... `var startTime = Date.now(); window.setInterval(() => console.log(Date.now() - startTime), 1000);` – epascarello Jul 30 '21 at 21:29

1 Answers1

2

If you set the start time as a variable, then you can calculate the the current time of the counter in the interval by subtracting the timestamp that you stored as a variable from the current time. So, then even if the interval pauses while the computer is locked, then when you unlock it and the interval resumes, it will calculate the correct time.

You could also use window.sessionStorage to store the start time. I have a timer I created in CodePen that uses session storage to store the values. You can see that here: https://codepen.io/steebn/pen/eYWrPeM

In the snippet below, I modified the code from that codepen to use a global variable instead of session storage since apparently you cannot use session storage in a snippet.

Hopefully this helps.

const qs = (selector) => document.querySelector(selector);
const qsa = (selector) => document.querySelectorAll(selector);

//variable to store the timestamps 
const tLog = {
  startTime: null,
  stopTime: null,
  duration: null
};

//variable to store the interval 
let timerInterval; 

//Add event listeners to each button
qsa(".timer").forEach((btn) => {
  btn.addEventListener("click", (event) => {
    qsa(`button.timer`).forEach((btn) => (btn.disabled = true));
    qs("#time").classList.remove(`paused`);
    switch (event.target.id) {
      case `start`:
        setMessage(`Timer Counting`);
        qsa(`button.started`).forEach((btn) => (btn.disabled = false));        
        tLog.startTime = tLog.duration ?
          new Date().getTime() - tLog.duration :
          new Date().getTime();
          
        //Start the timer interval  
        timerInterval = window.setInterval(() => {
          const currentTime = new Date().getTime();
          //Calculate duration using the starting timestamp in the tLog variable 
          qs("#time").innerText = getDuration(currentTime - tLog.startTime);
        }, 1000);
        
        break;
      case `stop`:
        setMessage(`Timer Complete`);
        qsa(`button.stopped`).forEach((btn) => (btn.disabled = false));
        window.clearInterval(timerInterval); //Clear the interval
        tLog.stopTime = new Date().getTime();
        tLog.duration = tLog.stopTime - tLog.startTime;
        break;
      case `pause`:
        qs(`#time`).classList.add(`paused`);
        setMessage(`Timer Paused`);
        qsa(`button.paused`).forEach((btn) => (btn.disabled = false));
        window.clearInterval(timerInterval);
        tLog.stopTime = new Date().getTime();
        tLog.duration = tLog.stopTime - tLog.startTime;
        break;
      case `reset`:
        qsa(`button.cleared`).forEach((btn) => (btn.disabled = false));
        qs("#time").innerText = `00:00:00`;
        qs("#time").classList.remove(`paused`);
        Object.keys(tLog).map((key) => (tLog.key = null));
        setMessage(`Timer is ready to begin`);
        break;
    }
  });
});

const setMessage = (msg) => (qs(".status").innerText = msg);

const getDuration = (timeStamp) => {
  const d = new Date(timeStamp);
  const H = d.getUTCHours().toString().padStart(2, 0);
  const M = d.getUTCMinutes().toString().padStart(2, 0);
  const S = d.getUTCSeconds().toString().padStart(2, 0);
  const s = d.getUTCSeconds().toString().padStart(3, 0);
  return `${H}:${M}:${S}`;
};
.btn {
  font-size: 3rem !important;
}

#time {
  position: relative;
  font-size: 4rem;
}

#time.paused {
  animation: animate 1.25s linear infinite;
}

@keyframes animate {
  0% {
    opacity: 0;
  }
  50% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}
<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.2/css/bootstrap.min.css' integrity='sha512-usVBAd66/NpVNfBge19gws2j6JZinnca12rAe2l+d+QkLU9fiG02O1X8Q6hepIpr/EYKZvKx/I9WsnujJuOmBA==' crossorigin='anonymous' />

<body class="bg-dark text-white">
  <header class="container d-flex my-0">
    <div class="btn-group btn-group-lg mx-auto" role="group" aria-label="Basic example">
      <button id="start" class="btn p-0 timer cleared paused">&#9654;&#65039;</button>
      <button id="pause" class="btn p-0 timer started" disabled>&#9208;&#65039;</button>
      <button id="stop" class="btn p-0 timer started paused" disabled>&#9209;&#65039;</button>
      <button id="reset" class="btn p-0 timer stopped" disabled>&#128259;</button>
    </div>
  </header>
  <main class="container d-flex my-0 flex-column">
    <div id="time" class="mx-auto">00:00:00</div>
    <div class="mx-auto status">Timer is ready to begin</div>
  </main>
</body>
Steve
  • 878
  • 1
  • 5
  • 9