0

I have a problem with some code I have been producing in JavaScript. I want to calculate the difference between two times on a 24 hour clock. The data comes from two input time fields:

<input type="time" id="start" />
<input type="time" id="end" />

Because of this the times come in a string 00:00, which doesn't help for number calculations.

The way I worked it out was to minus the start from the end. This works perfectly if the the end time is greater, however if the end time is past 11:00 (00:00), I end up with a negative number. I have tried adding 24 to the result if the end is lower than the start but I still get a negative number. This may seem like a dumb question but I was never that good at maths.

var numHours;
if(time_end < time_start){
    numHours = parseInt(t_e.substring(0,2)) - parseInt(t_s.substring(0,2)) + 24;
}else{
    numHours = parseInt(t_e.substring(0,2)) - parseInt(t_s.substring(0,2));
}

There is probably (definitely) a better way of doing this but how can I get this to work. Also could I calculate the minutes as well to get more accurate time difference.

Paul Ledger
  • 1,125
  • 4
  • 21
  • 46
  • Support for that isn't looking good: http://caniuse.com/input-datetime – bjb568 Nov 14 '13 at 00:27
  • just an idea but if the number is negative could I just sub string the - sign. Would That be the same? – Paul Ledger Nov 14 '13 at 00:27
  • 2
    Step #1 Convert everything into minutes. Step #2 Do math (how *should* different overlaps be handled?). Step #3 Convert back to display as required. – user2864740 Nov 14 '13 at 00:30
  • wow @Dude, I may as well use an plain input box, its going to work better cross platform. I have also created a date input using jquery-ui. It works on my tablets, should I change that too? – Paul Ledger Nov 14 '13 at 00:30
  • After a googling, I found [this](http://labs.perifer.se/timedatepicker/) – bjb568 Nov 14 '13 at 00:33
  • You're 'code sample' doesn't show where `t_e` and `t_s` come from. Anyway, you should be passing a radix to `parseInt` to define the base of the int to convert the string to. Otherwise you may have different bases (octal by default if it starts with `'0'`, I believe) and strange things happen with the math. Do `parseInt(num, 10)` instead. [Here's a different question about using parseInt which explains the gotcha](http://stackoverflow.com/q/850341/803925). – nbrooks Nov 14 '13 at 00:46

3 Answers3

3

The solutions provided aren't accounting for the day boundary effectively. And all of this assumes the difference is less than 24 hours. Meaning that we have an upper boundary on the difference between start and end of 23 hours and 59 minutes, otherwise we are confused by the result. But remember that as described a real use case is that an event starts at 11pm and ends at 1am (from 23:00 to 1:00) and the difference is 2 hours NOT 22 hours.

function calculateTime(e) {
   var startTime = $('#start').val();
   var endTime = $('#end').val();

   var startTimeArray = startTime.split(":");
   var startInputHrs = parseInt(startTimeArray[0]);
   var startInputMins = parseInt(startTimeArray[1]);

   var endTimeArray = endTime.split(":");
   var endInputHrs = parseInt(endTimeArray[0]);
   var endInputMins = parseInt(endTimeArray[1]);

   var startMin = startInputHrs*60 + startInputMins;
   var endMin = endInputHrs*60 + endInputMins;

   var result;

   if (endMin < startMin) {
       var minutesPerDay = 24*60; 
       result = minutesPerDay - startMin;  // Minutes till midnight
       result += endMin; // Minutes in the next day
   } else {
      result = endMin - startMin;
   }

   var minutesElapsed = result % 60;
   var hoursElapsed = (result - minutesElapsed) / 60;

   alert ( "Elapsed Time : " + hoursElapsed + ":" + (minutesElapsed < 10 ?
            '0'+minutesElapsed : minutesElapsed) ) ;
}

And I didn't check, but I believe you could just do this, but I'm not checking it :

var result = endMin - startMin;
if (result < 0 ) result = (24*60) + result;
mangr3n
  • 309
  • 1
  • 7
  • Why do things all ways look easier **after** somebody shows you first. Both methods work really well. I was miles off. – Paul Ledger Nov 14 '13 at 21:29
  • It has some hidden gotchas that aren't immediately apparent. I've worked on calendar and scheduling applications in the past transposing calendar events and meetings across timezones are another interesting issue. Remember the problem isn't the problem, the problem is figuring out how to think about the problem. Meaning, once you figure out how to look at it in a way that makes all of the edge conditions and ramifications clear, the solution just falls out on it's own. – mangr3n Nov 14 '13 at 23:12
1

A simple solution that might work best for this limited use-case is to convert both times into total minutes since the start of the day, and then subtract.

Pseudocode:

startMin = startInputHrs * 60 + startInputMin
endMin = endInputHrs * 60 + endInputMin

timeDifference = endMin - startMin

It's up to you how you want to handle a negative result. Maybe give the user an error message, and tell them that the start time has to come before the end time?

Matt Vukas
  • 3,225
  • 3
  • 26
  • 37
  • so basically in short terms minus each form 2400 then from each other to get a difference between the two time in mins and hours? – Paul Ledger Nov 14 '13 at 00:40
  • Not quite. If its a 24 hour clock, using my calculations we'll get the number of minutes from the beginning of the day (12:00am). Then you just subtract the earlier time (startMin) from the later time (endMin), and you'll get the time difference between the dates in minutes. You can then take divide that by 60 to get the hours that have passed, and take the mod 60 of that to get the number of minutes that have passed. Make sense? – Matt Vukas Nov 14 '13 at 02:19
  • If my answer helps you, please select it. Thanks – Matt Vukas Nov 14 '13 at 14:35
0

I'm a beginner, and some whiz is probably going to come up with an answer in like 2 lines :), but here it is.....this works. input is a string in the form of "1:20pm-2:30am".

function CountingMinutesI(str) { 
split = str.split('-')
startTime = split[0]
endTime = split[1]

// for end time
   if (endTime === '12:00am')  { endInMinutes = 0}
   else if (endTime.charAt(endTime.length-2) === 'a') {
     if (endTime.substr(0, 2) === '12') { 
       endInMinutes = parseInt(endTime.split(':')[1].replace(/[a-z]/gi, ''))
     }
     else {
     endHours = endTime.split(':')[0]
     endMins = endTime.split(':')[1].replace(/[a-z]/gi, '')
     endInMinutes = (parseInt(endHours)*60) + parseInt(endMins)
     }
   }

   else if (endTime === '12:00pm') {endInMinutes = 720}

   else {
     endHours = endTime.split(':')[0]
     endMins = endTime.split(':')[1].replace(/[a-z]/gi, '')
     endInMinutes = (parseInt(endHours)*60 + 720) + parseInt(endMins)
   }  

// for start time
   if (startTime === '12:00am')  { startInMinutes = 0}

   else if (startTime.charAt(startTime.length-2) === 'a') {
      if (startTime.substr(0, 2) === '12') { 
       startInMinutes = parseInt(startTime.split(':')[1].replace(/[a-z]/gi, ''))
      }
      else {
      startHours = startTime.split(':')[0]
      startMins = startTime.split(':')[1].replace(/[a-z]/gi, '')
      startInMinutes = (parseInt(startHours)*60) + parseInt(startMins)
      }  
    }

   else if (startTime.substr(0,2) === '12') {startInMinutes = 720 + parseInt(startTime.split(':')[1].replace(/[a-z]/gi, ''))}
   else {
     startHours = startTime.split(':')[0]
     startMins = startTime.split(':')[1].replace(/[a-z]/gi, '')
     startInMinutes = (parseInt(startHours)*60 + 720) + parseInt(startMins)
   }  

   if (endInMinutes > startInMinutes) {output = endInMinutes - startInMinutes}
   else {output = 1440 - (startInMinutes - endInMinutes)}

return output
}
Anthony
  • 21
  • 1
  • 4