Cris Cris - 6 months ago 97
jQuery Question

Datatables footer sum()

I'm trying to make a correct sum() of hh:mm:ss type of data, and i'm trying to understand why it has this behaviour when the minutes or seconds are getting >= 100. And how can i fix it?

correct:enter image description here
incorrect:enter image description here

This is the sum() function i took from Datatables forum:

jQuery.fn.dataTable.Api.register('sum()', function () {
return this.flatten().reduce(function (a, b) {
if (typeof a === 'string') {
a = a.replace(/[^\d.-]/g, '') * 1;
}
if (typeof b === 'string') {
b = b.replace(/[^\d.-]/g, '') * 1;
}
return a + b;
}, 0);
});


And this is the rest of the code full of conversions, and making my head spin.

var tempoPage = tempo.column(3, { page: 'current' })
.data()
.sum();
tempoPage = tempoPage.toString();

while (tempoPage.length < 6) {
tempoPage = "0" + tempoPage
}
tempoPage = tempoPage.replace(/^(\d+)(\d{2})(\d{2})$/, function (m, m1, m2, m3) {
m1 = Number(m1);
m2 = Number(m2);
m2 += parseInt(m3 / 60, 10);
m3 = m3 % 60; // get soconds
m1 += parseInt(m2 / 60, 10); //get hours
m2 = m2 % 60; // get minutes

//convert back to string
m2 = m2.toString();
m3 = m3.toString();
m1 = m1.toString();

while (m1.length < 2){
m1 = '0' + m1
}
while (m2.length < 2){
m2 = '0' + m2
}
while (m3.length < 2){
m3 = '0' + m3
}

return m1 + ':' + m2.slice(-2) + ':' + m3.slice(-2);
})
//write in footer
$(tempo.column(3)
.footer()).html(tempoPage);
},


Does any one see a better way to do this or can point me on the right track?
Thank you.

Answer

I cannot say what is wrong with the code. It seems really complicated, the only thing we need to do is to sum 3 values, and add for example 1 minute when seconds increases 60. Have made this less complicated sumHours() plugin, it seems to do the job (but have not tested in depth) :

jQuery.fn.dataTable.Api.register( 'sumHours()', function ( ) {
  function pad(int) {
    return int > 9 ? int.toString() : '0' + int.toString()
  }
  var t, hours = 0, mins = 0, secs = 0;
  for (var i=0; i<this.length; i++) {
    t = this[i].split(':')
    hours += parseInt(t[0])
    mins += parseInt(t[1])
    if (mins >= 60) {
       mins -= 60
       hours += 1
    }
    secs += parseInt(t[2])
    if (secs >= 60) {
       secs -= 60
       mins += 1
    }
  }  
  return pad(hours) + ':' + pad(mins) + ':' + pad(secs)
})

You can use this the same way as the as the official sum() example you hve linked to :

api.column( 0, {page:'current'} ).data().sumHours()

demo -> http://jsfiddle.net/vbuyjm9s/