How to sum float numbers in the format hours and minutes?

The best way to deal with "crazy" data formats like that is to first convert them into a sane and easily processable format, do whatever you need to do using the converted data and finally (if you absolutely have to) convert the results back to the original format.

(Of course, the real solution is to stop using such crazy time representations entirely. But that's not always practical, e.g. because you need to interface with a legacy system that you cannot change.)

In your case, a suitable sane format for your data would be e.g. an integral number of minutes. Once you've converted your data to this format, you can then do ordinary arithmetic on it.

// converts a pseudo-float of the form hh.mm into an integer number of minutes
// robust against floating-point roundoff errors, also works for negative numbers
function hhMmToMinutes(x) {
  const hhmm = Math.round(100 * x)  // convert hh.mm -> hhmm
  return 60 * Math.trunc(hhmm / 100) + (hhmm % 100)
}

// convert minutes back to hh.mm pseudo-float format
// use minutesToHhMm(minutes).toFixed(2) if you want trailing zeros
function minutesToHhMm(minutes) {
  return Math.trunc(minutes / 60) + (minutes % 60) / 100
}

const arr = [0.15, 0.2, 3.45, 0.4, 2, 0.3, 5.2, 1, 1.4, 1.1, 2.4, 1, 3.4]

let sum = 0
console.log( arr.map(hhMmToMinutes).map(x => sum += x).map(minutesToHhMm) )

Note that the conversion code above first multiplies the input float by 100 and rounds it to an integer before separating the hour and minute parts. This should robustly handle inputs with possible rounding errors while avoiding the need to stringify the inputs.

The reason for taking extra care here is because the number 0.01 = 1/100 (and most of its multiples) is not actually exactly representable in the binary floating-point format used by JavaScript. Thus you can't actually have a JS number that would be exactly equal 0.01 — the best you can have is a number that's so close that converting it to a string will automatically hide the error. But the rounding error is still there, and can bite you if you try to do things like comparing such numbers to a exact threshold. Here's a nice and simple demonstration:

console.log(Math.trunc(100 * 0.29))  // you'd think this would be 29...

// We got this after simple addition
// Now we want to change it into 4.2
sample = 3.8

// Now here are the minutes that the float currently shows
minutes = (sample % 1) * 100

// And the hours
hours = Math.floor(sample)

// Here are the number of hours that can be reduced from minutes
AddHours = Math.floor(minutes / 60)

// Adding them to the hours count
hours += AddHours

// Reducing mintues
minutes %= 60

// Finally formatting hour and minutes into your format
final = hours + (minutes / 100.0)
console.log(final)

You can use this logic after doing simple arithmetic addition, this will convert the sum into time format

Tags:

Javascript