Add hours as Moment.Js

I have a table with the following fields:

insert the description of the image here

But I do not want to work with date and time together, I would like to know if there is the possibility of the Moment.js add only the hours, without necessarily needing the date in the obtained variable.

Well, when I generate my query I bring my hours based on the dates recorded in the bank.

insert the description of the image here

My controller is currently like this:

public function get()
{
    $user = $_SESSION['nome'];

    $this->load->model('trackerModel');
    $query = $this->trackerModel->get($user)->result_array();

    foreach($query as $element){
        $result[$element['date']][] = $element;

    }   

    $data = [];
    foreach($result as $key=>$value){
        $data[] = [
            'date'=> $key,
            'item' => $value
        ];
    }
    echo json_encode($data);
}

And o my JSON, like this:

[{"date":"26-08-2019","item":[{"id":"78","hrStart":"11:09:00","hrEnd":"12:09:00","hrWork":"01:00:00","nome_user":"Diego ","date":"26-08-2019","cliente":"Marcelo","projeto":"Aplicativo Mobile","pacote":"Aplicativo Mobile","type":"Non-Billable","descri":"","hrTotal":""},{"id":"82","hrStart":"04:00:00","hrEnd":"07:00:00","hrWork":"03:00:00","nome_user":"Diego ","date":"26-08-2019","cliente":"Carlos","projeto":"TimeSheet","pacote":"TimeTrack","type":"programa\u00e7\u00e3o","descri":"","hrTotal":""}]}]

Hence my doubt, I want to take these hrWork and add, but I only want the total result of each date, so I can show the user how much he worked per day. Is that possible?

Author: hkotsubo, 2019-08-26

2 answers

First we need to understand two important concepts. Consider the two sentences below:

  • I started working at 8 o'clock in the morning
  • today I worked for 8 hours in a row

In the first case, "8 hours" refers to the time (a specific time of day). It's okay that he needs "in the morning" to be unambiguous (it could be 8 in the evening), but the fact is that it is referring to a specific time.

In the second case, " 8 hours " refers to the duration (an amount of time). It is not said What time I began to work. It is only the amount of time, without any relation to schedules.

These two concepts are not the same thing . A time (hour, minute, second, fractions of a second) refers to a specific time of a day. Durations are just amounts of time, which exist by themselves, without being tied to a specific date and time.

What confuses is the fact that both (both times and durations) use exactly the same words (days, hours, minutes, etc.), and are often written in the same way (a clock shows "08:00:00" when it is 8 am, a stopwatch shows "08:00:00" when the time count reaches eight hours).

Another point that can-mistakenly-make us think that schedules and durations are the same thing is that although they are different concepts, they can be related. If I calculate the difference between two dates and/or times, the result is a duration (knowing the date/time that started and that ended, I can calculate how long it lasted), and if I add a date/time with a duration, the result is another date/time (knowing the date/time that started and how long it lasted, I can calculate the date / time that ended).


That said, its fields hrStart and hrEnd are times (the time the job started and finished), while the field hrWork is a duration (the amount of time worked).

so the first point is that hrWork should not be saved as a TIME in the database, as it is not a schedule. Perhaps it should be saved as a number, containing the total amount of minutes (or seconds), for example. But anyway, this is a separate problem, let's go to the calculation itself.

Fortunately, a Moment.js has support for durations , so just get them from your JSON and go adding. For show the result in a more friendly format, you can download the version with locales:

let json = [{"date":"26-08-2019","item":[{"id":"78","hrStart":"11:09:00","hrEnd":"12:09:00","hrWork":"01:00:00","nome_user":"Diego ","date":"26-08-2019","cliente":"Marcelo","projeto":"Aplicativo Mobile","pacote":"Aplicativo Mobile","type":"Non-Billable","descri":"","hrTotal":""},{"id":"82","hrStart":"04:00:00","hrEnd":"07:00:00","hrWork":"03:00:00","nome_user":"Diego ","date":"26-08-2019","cliente":"Carlos","projeto":"TimeSheet","pacote":"TimeTrack","type":"programa\u00e7\u00e3o","descri":"","hrTotal":""}]}];

let duracaoTotal = moment.duration(0);
// percorrer os itens
json.forEach(obj => {
    obj.item.forEach(i => {
        duracaoTotal.add(moment.duration(i.hrWork));
    });
});
// usar o locale "pt" (português)
console.log(`Total: ${duracaoTotal.locale("pt").humanize()}`);

// ou formate o valor manualmente (nesse caso não precisa da versão com locales)
console.log(duracaoTotal.hours().toString().padStart(2, '0') + ':' +
            duracaoTotal.minutes().toString().padStart(2, '0') + ':' +
            duracaoTotal.seconds().toString().padStart(2, '0'));

// também é possível obter o total em minutos
console.log(duracaoTotal.asMinutes()); // 240
<script src="https://momentjs.com/downloads/moment-with-locales.min.js"></script>

Unfortunately there is not yet a method similar to format for durations ( as there is for dates), so you can use the version with locales to display to the user in a more user-friendly format, or format manually, if you need a specific format.

But to record in the bank, it is better save a single numeric value (such as total minutes, for example). In the above case, the total (returned by the asMinutes() method) is 240 minutes (which is equivalent to a duration of 4 hours), and this value could be saved in a numeric field (to restore the duration, just do moment.duration(240, 'minutes'), for example). Using a TIME type (representing a time) to save a duration is not ideal.


The above code makes a loop and sums everything it has in the JSON. But in your case, you that separate by date, then just make a small adaptation:

// versão simplificada, com os campos que vou usar, apenas para fins didáticos
let json = [
    {"date" : "26-08-2019",
     "item" : [
         {"hrWork":"01:00:00","date":"26-08-2019"}, 
         {"hrWork":"03:00:00","date":"26-08-2019"}
     ]
    },
    {"date" : "27-08-2019",
     "item" : [
         {"hrWork":"02:00:00","date":"27-08-2019"}, 
         {"hrWork":"01:30:00","date":"27-08-2019"}
     ]
    }
];

let totais = {};
// percorrer os itens
json.forEach(obj => {
    obj.item.forEach(i => {
        if (! totais[i.date]) {
            totais[i.date] = moment.duration(0);
        }
        totais[i.date].add(moment.duration(i.hrWork));
    });
});

Object.keys(totais).forEach(d => {
    let duracaoTotal = totais[d];
    console.log(`Total do dia ${d}: ` +
                duracaoTotal.hours().toString().padStart(2, '0') + ':' +
                duracaoTotal.minutes().toString().padStart(2, '0') + ':' +
                duracaoTotal.seconds().toString().padStart(2, '0'));
});
<script src="https://momentjs.com/downloads/moment.min.js"></script>

Notice that now I did not use the version with locales, but the moment.min.js, because I did not use the method humanize (instead I formatted the value manually).

And now an object totais has been created, whose keys are the dates and values are the respective totals of each day.

 4
Author: hkotsubo, 2019-08-27 12:45:04

You can calculate the difference in minutes between the "two hours" and then add the difference in the new time.

// hora inicial
var hrStart = '10:00';
// hora final
var hrEnd = '11:02';
// hora que você vai somar
var hfFoo = '20:00';

// Calcula a diferença em minutos entre os dois tempos 
var diffInMinutes = moment(hrEnd,"HH:mm").diff(moment(hrStart,"HH:mm"), 'minutes');

// Adiciona os minutos na hora desejada
var totalTime = moment(hfFoo, 'HH:mm').add(diffInMinutes, 'minutes').format('HH:mm');

console.log(totalTime);

// 21:02
 2
Author: Kayo Bruno, 2019-08-26 16:44:57