You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:用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;

学习建议

  1. 日期处理核心:重点掌握JavaScript Date对象的getDate()、setDate()、getDay()方法,以及toDateString()用于日期比较(规避时间部分干扰)。
  2. 模块化拆分:将复杂逻辑拆分为独立小函数(如节假日判断、时间差计算),提升代码可读性和复用性。
  3. 调试技巧:用console.log()打印关键变量(当前日期、节假日状态、当日工时),或通过浏览器开发者工具单步调试定位问题。
  4. 边界测试:重点测试以下场景:
    • 起始与结束日期为同一天
    • 日期范围包含周末/节假日
    • 仅起始日或仅结束日未勾选全日框
  5. 输入验证:添加基础验证(如结束日期不早于起始日期、结束时间不早于开始时间),避免非法输入导致计算错误。

内容的提问来源于stack exchange,提问作者angelman26

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 20:40:53