javascriptsetintervaltime-and-attendance

SetInterval doesn't take the exact time which was specified


I have been trying to create an attendance system that prompts a user for check-in and check out. Based on the input given, I have assigned a value time which increments by 1 after 1000 milliseconds(You can check in the code). But it is not working the way it has to. If I give check in and after one hour it doesn't show 1 hour. It is a bit slow than the actual time taken. I am not sure where the fault is. Please help me. For clarifications, I have concatenated the time and time taken after each second which you can see in the page itself. Thanks in advance!

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<style>
  body {
    background: black;
    color: #fcbe24;
    padding: 0 24px;
    margin: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    font-size: 18px;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
  }
  
  button {
    font-size: 25px;
  }
</style>

<body>
  <h1 id="header"></h1>
  <div>
    <button id="start" style="display:block;" onclick="startTimer()">Check-in</button>
    <button id="stop" style="display:none;" onclick="stopTimer()">Check-out</button>
  </div>
  <div id="time"></div>
</body>
<script>
  var time = 0;
  var startInterval;

  function startTimer() {
    if (time == 0) document.getElementById("time").innerHTML = "00:00:00";
    startInterval = setInterval(startTime, 1000);
    document.getElementById('start').style.display = 'none';
    document.getElementById('stop').style.display = 'block';
  }

  function stopTimer() {
    clearInterval(startInterval);
    document.getElementById('start').style.display = 'block';
    document.getElementById('stop').style.display = 'none';
  }

  function startTime() {
    time++;
    var seconds = time % 60;
    var minutes = Math.floor(time / 60) % 60;
    var hours = Math.floor(Math.floor(time / 60) / 60) % 24;
    console.log(seconds, minutes, hours);
    if (seconds < 10) seconds = "0" + seconds.toString();
    else seconds = seconds.toString();
    if (minutes < 10) minutes = "0" + minutes.toString();
    else minutes = minutes.toString();
    if (hours < 10) hours = "0" + hours.toString();
    else hours = hours.toString();
    var currentdate = new Date();
    var datetime = currentdate.getHours() + ":" +
      currentdate.getMinutes() + ":" +
      currentdate.getSeconds();
    document.getElementById("time").innerHTML += "<br>" + datetime + ", " + hours + ":" + minutes + ":" + seconds;
  }
</script>

</html>


Solution

  • The current mainstream operating systems are not real-time OSes. They cannot guarantee that, if a program asks them to be notified after X milliseconds, it will be notified after exactly X milliseconds. They guarantee only that the program will be notified and that will not happen before X milliseconds pass.

    The programs usually rely on timers provided by the operating system to do their time-related work.

    Even if they do not do that, because the multitasking means that a program does not run continuously but it is interrupted by the OS, put to sleep then resumed later, the programs cannot guarantee that a time interval of X milliseconds will take exactly X milliseconds either. More than than, in order to be as close as possible, the programs must rely on the OS timers to be waked up when the time comes.

    All in all, no program (on the mainstream operating systems) can guarantee that a time interval of X milliseconds will take exactly X milliseconds; you can rely, however, on the fact that it won't take less than X milliseconds.

    In order to achieve your goal regarding time measurement (whatever that goal is), you need to carefully measure the time like this:

    1. Get the current time and store it.
    2. Set a timeout or an interval, as you need.
    3. When the timeout passes and your callback is called, get the current time again.
    4. If the difference between the two times is different than the length of your timeout or interval then adjust the length of the next timeout to compensate, if your processing needs that. Or just remember the difference and adjust it later. This depends entirely on your goal and on the way you implement it (timeout or interval).

    If I give check in and after one hour it doesn't show 1 hour.

    Adjust/correct it periodically, every time your callback is invoked and it will show 1 hour.