Search code examples
javascriptjquerycountdown

how to create a realtime countdown effect to the time left between a start and end time inside a table?


I have search the internet before asking this. But I never found any duplicate question nor answer in stackoverflow.

let's say I have a start time

5:00 AM

Then I have an end time

6:15 AM

given the start and end time above, how to make a countdown effect to the time remaining in between the start and end time. the out put I want is something like e.g

01:14:01

(that one above means, there's only 1 hour and 14 minutes left before the countdown hit the end time value) That output will be written to an inside one of the of each row of data inside the table...the row of table is unlimited

e.g

<table>
<tr>
    <td>blhblah</td>
    <td>THE OUTPUT GOES HERE</td>
    <td>start time</td>
    <td>end time</td>
</tr>
<tr>
    <td>blhblah</td>
    <td>THE OUTPUT GOES HERE</td>
    <td>start time</td>
    <td>end time</td>
</tr>
<tr>
    <td>blhblah</td>
    <td>THE OUTPUT GOES HERE</td>
    <td>start time</td>
    <td>end time</td>
</tr>
</table>

my code to get the start time and end time for each row is like this

$('td:nth-child(3)').each(function() {

    var start_time = $.trim($(this).closest("tr").find('td:eq(7)').text());
    var end_time = $.trim($(this).closest("tr").find('td:eq(8)').text());


     //THE OUTPUT COUNTDOWN SHOULD BE HERE
     $(this).closest("tr").find('td:eq(6)').text(OUTPUT HERE);
 });

Solution

  • Update VII

    jQuery(document).ready(function($) {
    
       let startTime = new Date()      //this line means doing timespan calculation with System Clock 
       let elems = $('#timerTable tr')
       
       elems.each(function(index) {
         if(index !==0)
         {
            let endTime = $(this).children().eq(3).text()
            //$(this).children().eq(2).text(getStartTimeHours(startTime))  //delete this line
            
            createCountDownTimer(startTime,endTime,$(this).children().eq(1))
         }
       });
    
       function getStartTimeHours(d){
           let ampm
           let cHours
           let cMinutes = d.getMinutes()
    
           if(d.getHours()>11)
           {
             cHours = d.getHours()-12
             ampm = "PM"
           }
           else
           {
             cHours = d.getHours()
             ampm = "AM"
           }
           
           return cHours+":"+cMinutes+" "+ampm
       }
       
       function createCountDownTimer(startTime, endTime, elem)
       {
          //let tempSt = startTime
          let tempEt = endTime
       
          //use current Date as token
       
          let tempDate = new Date()
          let cYear = tempDate.getFullYear()
          let cMonth = Number(tempDate.getMonth()+1)
          let cDate = tempDate.getDate()
       
          //use current Date as token
       
          console.log(cYear+"-"+cMonth+"-"+cDate)
       
          //let sT = new Date(cYear+"-"+cMonth+"-"+cDate+" "+tempSt);
          let sT = startTime
          let eT = new Date(cYear+"-"+cMonth+"-"+cDate+" "+tempEt);
          let timeSpan
       
       
          //***************************************************************************
          // This section is for the situation of date acrossing, if startTime later then endTime, then assume that endTime means hour in tomorrow and startTime means hour of today.
          // If you want this function, then replace this line :
          
             timeSpan = eT.getTime()-sT.getTime()    
          
          // with follow section:
          
          
          //if(eT.getTime()-sT.getTime()<0)
          //{
          //   let newET = new Date(cYear+"-"+cMonth+"-"+cDate+" "+tempEt);
          //   timeSpan = (newET.getTime()-sT.getTime())+1000*60*60*24  
          //}
          //else
          //{
          //   timeSpan = eT.getTime()-sT.getTime()
          //}
          
          //***************************************************************************
           
          
           
            let myVar = setInterval(countDownTimer, 1000);
            
          function countDownTimer(){
       
            
            timeSpan = timeSpan-1000
            let hours = Math.floor(timeSpan /(1000*60*60))
            let minutes = Math.floor((timeSpan % (1000*60*60)) / (1000*60))
            let seconds = Math.floor(((timeSpan % (1000*60*60)) % (1000*60)) / 1000)
            let countDownOutput = hours+":"+minutes+":"+seconds
            
            if(timeSpan < 1000)   //if countdown equal 0 second, stop timer
            {
               elem.text("-")
               console.log("stop")
               clearInterval(myVar)
            }
            else
            {
               elem.text(countDownOutput)
            }    
          }
       } 
       
       
    });
    td {
     width:150px;
     text-align:left
    }
    
    th {
     width:150px;
     text-align:left
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <div>
      <table id="timerTable">
         <tr>
           <th>FLIGHT (No.)</th><th>REMINDING TIME</th><th>ARRIVAL</th><th>DEPARTURE</th>
         </tr>
         <tr>
           <td>CM 106</td><td></td><td>default time</td><td>7:30 PM</td>
         </tr>
         <tr>
           <td>SL 6204</td><td></td><td>default time</td><td>5:30 PM</td>
         </tr>
         <tr>
           <td>KL 552</td><td></td><td>default time</td><td>2:03 PM</td>
         </tr>
      </table>
    </div>

    Update V

    If you wanna show "-" when timer stop, then tune function countDownTimer():

      function countDownTimer(){
    
         //if(timeSpan < 2000)   //if countdown equal 0 second, stop timer
         //{
         //   console.log("stop")
         //   clearInterval(myVar)
         //}
         timeSpan = timeSpan-1000
         let hours = Math.floor(timeSpan /(1000*60*60))
         let minutes = Math.floor((timeSpan % (1000*60*60)) / (1000*60))
         let seconds = ((timeSpan % (1000*60*60)) % (1000*60)) / 1000
         let countDownOutput = hours+":"+minutes+":"+seconds
        //  $("#"+domID).text(countDownOutput)
        //if (isNaN(countDownOutput)) {
        //    elem.text('-');
        //} else {
        //    elem.text(countDownOutput);     
        //}
        if(timeSpan < 1000)   //if countdown equal 0 second, stop timer
        {
           elem.text('-');
           console.log("stop")
           clearInterval(myVar)
        }
        else
        {
          elem.text(countDownOutput);
        } 
       }
    

    And beware parameters of function createCountDownTimer(startTime, endTime, elem):

    1. parameter elem should ref to only one Dom Element obj, not an array of Dom Element.

    2. parameter startTime and endTime shoud be string, and must be like : "10:45 PM", "10:45:00 PM", "22:45:00", otherwise it would crash. Pattern like "9 April 2020 10:45:00 PM" is also wrong.

    Update IV

    It's close to solve this question.

    Your code

    $('td:nth-child(3)').each(function() {
    
        var start_time = $.trim($(this).closest("tr").find('td:eq(7)').text());
        var end_time = $.trim($(this).closest("tr").find('td:eq(8)').text());
    
    
        //THE OUTPUT COUNTDOWN SHOULD BE HERE
        //$(this).closest("tr").find('td:eq(6)').text(OUTPUT HERE);
        // the line above shouldn't be called here, appending countdown output  should place inside setInterval.
    
        createCountDownTimer(start_time, end_time, $(this).closest("tr").find('td:eq(6)'))
        //No need to pass domID, but pass domElement
    });
    

    Then need to tune function to append to domElement, instead of domID:

    function createCountDownTimer(startTime, endTime, domID)

    alter to

    function createCountDownTimer(startTime, endTime, domElement)

    Then alter function countDownTimer() :

        function countDownTimer(){
        ....
        ....
        ....
           //$("#"+domID).text(countDownOutput)
           domElement.text(countDownOutput)
        }
    

    Then it should work.

    Update III

    Append timer to table row, you could try code below:

    Update II

    answer question:

    1 March 2011 just a temp token, in order to create Date Obj, then use two Date objs (sT, eT) to calculate timeSpan. So, the date isn't matter, you could use any date at any month and any year as token.

    If you wannna use current Date as token, then check the code below, I have updated.

    Update I

    You could use time form : "1:00 PM" or "1:00:01 PM" or "13:00" or "13:00:01" , all work fine.

    Update1: if endTime is smaller then startTime, such as endTime: 6:00 AM startTime: 11:00 PM, then assume that endTime means tomorrow 6:00 AM and startTime as today 11:00 PM.

    Update2: Add countdown timer stop function. When countdown equal 0 seconds, stop timer.

    You could try codes below :

    jQuery(document).ready(function($) {
    
       let timeTableArray = [
          {  
             title:"Timer 1",
             start:"10:00 AM",
             end:"11:00 AM"
          },
          {
             title:"Timer 2",
             start:"9:00 PM",
             end:"1:00 AM"
          },
          {
             title:"Timer 3",
             start:"11:10:00 PM",
             end:"11:10:05 PM"
          }
       ]
    
       timeTableArray.forEach((timer,index)=>{
         $("#timerTable").append('<tr><td class="cell">'+timer.title+'</td><td class="cell"><span id="timer'+index+'"></span></td><td class="cell">'+timer.start+'</td><td class="cell">'+timer.end+'</td></tr>')
         
         createCountDownTimer(timer.start, timer.end, "timer"+index)
       
       })
       
       function createCountDownTimer(startTime, endTime, domID)
       {
       
          let tempSt = startTime
          let tempEt = endTime
       
          //use current Date as token
       
          let tempDate = new Date()
          let cYear = tempDate.getFullYear()
          let cMonth = Number(tempDate.getMonth()+1)
          let cDate = tempDate.getDate()
       
          //use current Date as token
       
          console.log(cYear+"-"+cMonth+"-"+cDate)
       
          let sT = new Date(cYear+"-"+cMonth+"-"+cDate+" "+tempSt);
          let eT = new Date(cYear+"-"+cMonth+"-"+cDate+" "+tempEt);
          let timeSpan
       
       
          if(eT.getTime()-sT.getTime()<0)
          {
             let newET = new Date(cYear+"-"+cMonth+"-"+cDate+" "+tempEt);
             timeSpan = (newET.getTime()-sT.getTime())+1000*60*60*24  
             //if startTime later then endTime, then assume that endTime means hour in tomorrow and startTime means hour of today.
    
          }
          else
          {
             timeSpan = eT.getTime()-sT.getTime()
          }
     
           
            let myVar = setInterval(countDownTimer, 1000);
            
          function countDownTimer(){
       
            if(timeSpan < 2000)   //if countdown equal 0 second, stop timer
            {
               console.log("stop")
               clearInterval(myVar)
            }
            timeSpan = timeSpan-1000
            let hours = Math.floor(timeSpan /(1000*60*60))
            let minutes = Math.floor((timeSpan % (1000*60*60)) / (1000*60))
            let seconds = ((timeSpan % (1000*60*60)) % (1000*60)) / 1000
            let countDownOutput = hours+":"+minutes+":"+seconds
            $("#"+domID).text(countDownOutput)
          }
       } 
       
    });
    .cell {
     width:150px
    
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <div>
      <table id="timerTable">
      </table>
    </div>