求助:用JavaScript实现符合规则的工时计算功能
工时计算JavaScript解决方案及实现
需求规则
- 每个完整工作日计7.5小时
- 跳过周末(周六、周日)及联邦节假日,不计工时
- 勾选「全日」复选框时,忽略对应日期的时间选择器数值;未勾选时,按时间选择器的时段计算当日工时
- 示例:2023年10月23日至27日(5个工作日),均勾选全日框时总工时为37.50;仅起始日未勾选且时段为12:00-16:30时,总工时为34.50(4个全日7.5小时 + 4.5小时起始日时段)
完整代码实现
HTML部分(含事件绑定)
<div class="col-md-6"> <label for="startDate" class="ml-4" style="margin-top: 20px;">When does it begin?</label> <div class="input-group"> <input type="date" id="startDate" class="form-control" value="<%= DateTime.Now.ToString("yyyy-MM-dd") %>" onchange="calculateHours()"> </div> <label for="startTime1" class="mt-2">From:</label> <input type="time" id="startTime1" class="form-control" value="07:00" disabled onchange="calculateHours()"> <label for="startTime2" class="mt-2">To:</label> <input type="time" id="startTime2" class="form-control" value="14:30" disabled onchange="calculateHours()"> <label class="CheckBoxContainer" style="font-size:20px"> <input type="checkbox" id="allDayCheckbox1" checked="checked" onchange="toggleTimePickers('startTime1', 'startTime2', this); calculateHours()"> <span class="checkmark"></span>All Day </label> </div> <div class="col-md-6"> <label for="endDate" class="ml-4" style="margin-top: 20px;">When does it end?</label> <div class="input-group"> <input type="date" id="endDate" class="form-control ml-4" value="<%= DateTime.Now.ToString("yyyy-MM-dd") %>" onchange="calculateHours()"> </div> <label for="endTime1" class="mt-2 ml-4">From:</label> <input type="time" id="endTime1" class="form-control ml-4" value="07:00" disabled onchange="calculateHours()"> <label for="endTime2" class="mt-2 ml-4">To:</label> <input type="time" id="endTime2" class="form-control ml-4" value="14:30" disabled onchange="calculateHours()"> <label class="CheckBoxContainer" style="font-size:20px"> <input type="checkbox" id="allDayCheckbox2" checked="checked" onchange="toggleTimePickers('endTime1', 'endTime2', this); calculateHours()"> <span class="checkmark"></span>All Day </label> </div> <input type="text" id="hoursRequested" class="form-control" readonly="">
JavaScript部分
// 控制时间选择器启用/禁用 function toggleTimePickers(startTimeId, endTimeId, checkbox) { const startTimeInput = document.getElementById(startTimeId); const endTimeInput = document.getElementById(endTimeId); startTimeInput.disabled = checkbox.checked; endTimeInput.disabled = checkbox.checked; } // 定义联邦节假日(示例为2023年,可根据需求扩展) const federalHolidays = [ new Date('2023-01-02'), new Date('2023-01-16'), new Date('2023-02-20'), new Date('2023-05-29'), new Date('2023-06-19'), new Date('2023-07-04'), new Date('2023-09-04'), new Date('2023-10-09'), new Date('2023-11-10'), new Date('2023-11-23'), new Date('2023-12-25') ]; // 判断是否为节假日 function isHoliday(date) { const dateStr = date.toDateString(); return federalHolidays.some(holiday => holiday.toDateString() === dateStr); } // 计算两个时间字符串的小时差 function calculateTimeDiff(fromTime, toTime) { const [fromH, fromM] = fromTime.split(':').map(Number); const [toH, toM] = toTime.split(':').map(Number); const totalFrom = fromH * 60 + fromM; const totalTo = toH * 60 + toM; return (totalTo - totalFrom) / 60; } // 核心工时计算函数 function calculateHours() { const startDate = new Date(document.getElementById('startDate').value); const endDate = new Date(document.getElementById('endDate').value); const allDay1 = document.getElementById('allDayCheckbox1').checked; const allDay2 = document.getElementById('allDayCheckbox2').checked; const startFrom = document.getElementById('startTime1').value; const startTo = document.getElementById('startTime2').value; const endFrom = document.getElementById('endTime1').value; const endTo = document.getElementById('endTime2').value; const resultInput = document.getElementById('hoursRequested'); let totalHours = 0; let currentDate = new Date(startDate); while (currentDate <= endDate) { const dayOfWeek = currentDate.getDay(); const isWeekend = dayOfWeek === 0 || dayOfWeek === 6; // 跳过周末和节假日 if (isWeekend || isHoliday(currentDate)) { currentDate.setDate(currentDate.getDate() + 1); continue; } const isStartDay = currentDate.toDateString() === startDate.toDateString(); const isEndDay = currentDate.toDateString() === endDate.toDateString(); if (isStartDay && isEndDay) { // 起始和结束为同一天 let dayHours = 7.5; if (!allDay1) { dayHours = calculateTimeDiff(startFrom, startTo); } else if (!allDay2) { dayHours = calculateTimeDiff(endFrom, endTo); } totalHours += dayHours; } else if (isStartDay) { // 仅起始日 totalHours += allDay1 ? 7.5 : calculateTimeDiff(startFrom, startTo); } else if (isEndDay) { // 仅结束日 totalHours += allDay2 ? 7.5 : calculateTimeDiff(endFrom, endTo); } else { // 中间工作日 totalHours += 7.5; } currentDate.setDate(currentDate.getDate() + 1); } resultInput.value = totalHours.toFixed(2); } // 页面加载时执行初始计算 window.onload = calculateHours;
学习建议
- 日期处理核心:重点掌握JavaScript Date对象的
getDate()、setDate()、getDay()方法,以及toDateString()用于日期比较(规避时间部分干扰)。 - 模块化拆分:将复杂逻辑拆分为独立小函数(如节假日判断、时间差计算),提升代码可读性和复用性。
- 调试技巧:用
console.log()打印关键变量(当前日期、节假日状态、当日工时),或通过浏览器开发者工具单步调试定位问题。 - 边界测试:重点测试以下场景:
- 起始与结束日期为同一天
- 日期范围包含周末/节假日
- 仅起始日或仅结束日未勾选全日框
- 输入验证:添加基础验证(如结束日期不早于起始日期、结束时间不早于开始时间),避免非法输入导致计算错误。
内容的提问来源于stack exchange,提问作者angelman26
相关产品推荐
相关产品推荐

