Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

javascript

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

Those. if calculate two such numbers 0.35+3.45 then it should be = 4.20, not 3.80

var arr = [0.15, 0.2, 3.45, 0.4, 2, 0.3, 5.2, 1, 1.4, 1.1, 2.4, 1, 3.4]
    
var sum = 0.0;
    
arr.forEach(function(item) {
  console.log(sum);
  sum += parseFloat(item);
});

The result should be like this:

0
0.15
0.35
4.20
5.0
7.0
7.30
12.50
13.50
15.30
16.40
19.20
20.20
like image 618
user12916796 Avatar asked Feb 19 '20 05:02

user12916796


4 Answers

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...
like image 68
Ilmari Karonen Avatar answered Nov 03 '22 20:11

Ilmari Karonen


// 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

like image 30
Letsintegreat Avatar answered Nov 03 '22 19:11

Letsintegreat


You need to convert everything either into hours or into minutes and then do the math.

Example: 0.35 + 3.45
Convert 0.35 to Hours Number((35/60).toFixed(2))
= 0.58

Then convert 3hours 45 minutes into hours
= 3 + Number((45/60).toFixed(2))
= 3hours + 0.75 hours
= 3.75

Add the 2 conversions
= 0.58 + 3.75
= 4.33 hours

Convert the 0.33 back to minutes by multiplying by 60
= 4 hours 19.8 minutes ~ 20 mins

Hope that helps!
like image 37
Kaustubh - KAY Avatar answered Nov 03 '22 20:11

Kaustubh - KAY


Here you go, implementation in Javascript ES6. I looped each element, and splits hours, minutes by ., checked if minutes is non-existing else assign 0 count the total of hours and minutes and applied necessary computation.

const resultObj = [0.35, 3.45].reduce((a, e) => {
  const [hours, minutes] = e.toString().split('.');
  a.h += +hours;
  a.m += (+(minutes.padEnd(2, 0)) || 0); 
  return a;
}, {h: 0, m: 0});


const result = resultObj.h + Math.floor(resultObj.m / 60) + ((resultObj.m % 60) / 100);
console.log(result);
like image 31
onecompileman Avatar answered Nov 03 '22 19:11

onecompileman