I’m trying to calculate the shift hours in a day, accounting for different types of shifts (Normal, Evening, and Night), and also considering overlapping break times during those shifts. Here’s the breakdown of the shifts:
- Normal Hours: From 06:00 – 18:00. A 30-minute break occurs between
12:00 – 12:30. - Evening Hours: From 18:00 – 21:00. A 30-minute break
occurs between 20:00 – 20:30. - Night Hours: From 21:00 – 06:00. A
30-minute break occurs between 04:00 – 04:30.
Break Time Rules:
- If the shift is less than 6 hours, no break is given.
- If the shift is 6 hours and break time is between this interval, a 20-minute break is provided.
- For shifts that are longer than 6 hours and break time is between this interval, a 30-minute break is provided.
I need to calculate the hours worked in each shift category. Hers is the code which partly works:
function calculateShiftHours(startShift, endShift) {
const parseTime = (timeStr) => {
const [hours, minutes] = timeStr.split(":").map(Number);
return hours * 60 + minutes;
};
const formatHours = (minutes) => (minutes / 60).toFixed(2);
const NORMAL_START = parseTime("06:00");
const NORMAL_END = parseTime("18:00");
const EVENING_START = parseTime("18:00");
const EVENING_END = parseTime("21:00");
const NIGHT_START = parseTime("21:00");
const NIGHT_END = parseTime("06:00");
const BREAK_TIMES = {
normal: { start: parseTime("12:00"), end: parseTime("12:30") },
evening: { start: parseTime("20:00"), end: parseTime("20:30") },
night: { start: parseTime("04:00"), end: parseTime("04:30") },
};
const startTime = parseTime(startShift);
const endTime = parseTime(endShift) < startTime ? parseTime(endShift) + 1440 : parseTime(endShift);
const shiftDuration = endTime - startTime;
let breakDuration = 0;
if (shiftDuration >= 6 * 60 && shiftDuration < 6.5 * 60) breakDuration = 20;
else if (shiftDuration >= 6.5 * 60) breakDuration = 30;
const calculateOverlap = (start, end, rangeStart, rangeEnd) => {
const overlapStart = Math.max(start, rangeStart);
const overlapEnd = Math.min(end, rangeEnd);
return Math.max(0, overlapEnd - overlapStart);
};
const calculateShiftHoursInRange = (rangeStart, rangeEnd) => {
return calculateOverlap(startTime, endTime, rangeStart, rangeEnd);
};
let normalHours = calculateShiftHoursInRange(NORMAL_START, NORMAL_END);
let eveningHours = calculateShiftHoursInRange(EVENING_START, EVENING_END);
let nightHours = calculateShiftHoursInRange(NIGHT_START, NIGHT_END + 1440);
if (breakDuration > 0) {
if (calculateOverlap(startTime, endTime, BREAK_TIMES.normal.start, BREAK_TIMES.normal.end) > 0) {
normalHours -= breakDuration;
} if (calculateOverlap(startTime, endTime, BREAK_TIMES.evening.start, BREAK_TIMES.evening.end) > 0) {
eveningHours -= breakDuration;
} if (calculateOverlap(startTime, endTime, BREAK_TIMES.night.start, BREAK_TIMES.night.end) > 0) {
nightHours -= breakDuration;
}
}
return {
normal: formatHours(normalHours),
evening: formatHours(eveningHours),
night: formatHours(nightHours)
};
}
function testShiftCalculation(){
const result = calculateShiftHours("22:00", "07:00");
console.log(result); // Test for a normal shift with break (Expected output should adjust with break time)
}
It works well when start time is less than end time. for example if shift is between 06:00-24:00. But it calculates incorrectly when the shift starts from midnight, for example:
const result = calculateShiftHours("22:00", "07:00");
The output should be:
Normal hours: 1 hrs (06:00-07:00)
Evening hours: 0
Night hours: 8 hrs (22:00-06:00)
Since shift is 9 hour long and 04:00-04:30 overlaps with Night hours so, 30 minutes deduction.
Final output should be: {normal:'1',evening:'0',night: '7.5'}
But the script output is: { normal: '0.00', evening: '0.00', night: '8.00' }
So, the issue is, it does not calculate hours and break time deduction correctly when shift start time is in current day and shift end time is in next day. Any suggestion would be much appreciated.
2
Answers
I have been able to get around this limitation by adding a few checks when shift end time move into the next day morning. Here is the modified code, that works well for all intervals along with break dedcutions:
These added checks, explicitly get start and end time, compare them with the break intervals and then compile the results, any suggestions to improve the overall efficiency of the script would be much appreciated.
This is because when a shift starts in one day and ends in the next, it complicates calculations, especially with break deductions. So, to fix this you would need to
Try these 2 approaches and see if your issue is fixed. I didnt had enough time to implement a code snippet. So, i explained it here. If i get time i will update the solution here.