First we need to understand two important concepts. Consider the two sentences below:
- I started working at 8 am
- today I worked for 8 hours straight
In the first case, "8 hours" refers to timetable (a specific moment of the day). It’s okay that it needs "morning" not to be ambiguous (it could be 8 at night), but the fact is that it’s referring to a specific moment.
In the second case, "8 hours" refers to duration (an amount of time). It is not said what hours I started working. It is only the amount of time with no relation to schedules.
These two concepts are not the same thing. A time (hour, minute, second, fractions of a second) refers to a specific moment 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 o'clock).
Another point that can - erroneously - make us think that times and durations are the same thing is that, although they are different concepts, they may 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 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, their fields hrStart
and hrEnd
are times (the time when started and finished the work), while the field hrWork
is a duration (the amount of time worked).
So the first point is that hrWork
should not be kept as a TIME
in the database, because it’s not a schedule. Perhaps it should be stored as a number, containing the total amount of minutes (or seconds), for example. But anyway, this is a problem aside, let’s go to the calculation itself.
Fortunately, Moment.js supports durations, then just get them from your JSON and add them up. To show the result in a more user-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 still no method similar to format
for durations (as there is for dates), then you can use the version with locales to display to the user in a more user-friendly format, or manually format if you need a specific format.
But to record in the bank, it is better to keep a single numerical value (like the total of minutes, for example). In the above case, the total (returned by the method asMinutes()
) is 240 minutes (equivalent to a duration of 4 hours), and this value could be stored in a numerical field (to restore the duration, just do moment.duration(240, 'minutes')
, for example). Use a type TIME
(that represents a time) to save a duration is not ideal.
The code above makes a loop and sums up everything you have in JSON. But in your case, you want to separate by date, so 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>
Note that now I have not used the version with locales, and yes the moment.min.js
, because I didn’t use the method humanize
(instead I formatted the value manually).
And now an object has been created totais
, whose keys are the dates and values are the respective totals of each day.
const Endtime = Moment(hrStart, 'HH:mm:ss'). add(durationInMinutes, 'minutes'). format('HH:mm');
– danilo