js计算请假时长,去除上下班以外的时长、周末、节假日

618 阅读1分钟
最近公司做的一个请假模块,需要计算出请假时间,在网上查找了很多资料,都没有详细完整的实现方式,我就尝试自己写了一下

代码中用到了moment.js,不要忘了引入哦,不啰嗦,直接上代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    
</body>
<script src="https://cdn.bootcdn.net/ajax/libs/moment.js/2.29.4/moment.min.js"></script>
<script>
    /**
     * 计算请假时长
     *
     * @param {Object} options - 计算请假时长的配置选项
     * @param {string} options.startTime - 请假开始时间(必填,格式为 'YYYY-MM-DD HH:mm')
     * @param {string} options.endTime - 请假结束时间(必填,格式为 'YYYY-MM-DD HH:mm')
     * @param {string} [options.workStartTime='08:30'] - 上班时间(可选,默认为 '08:30',格式为 'HH:mm')
     * @param {string} [options.workEndTime='17:30'] - 下班时间(可选,默认为 '17:30',格式为 'HH:mm')
     * @param {string} [options.restStartTime='12:00'] - 午休开始时间(可选,默认为 '12:00',格式为 'HH:mm')
     * @param {string} [options.restEndTime='12:00'] - 午休结束时间(可选,默认为 '12:00',格式为 'HH:mm',默认无午休时间)
     * @param {number[]} [options.workdays=[1,2,3,4,5]] - 工作日数组(可选,默认为 [1,2,3,4,5])
     * @param {string[]} [options.excludeHolidays=[]] - 去除的节假日数组(可选,默认为空数组,格式为 'YYYY-MM-DD')
     * @returns {number} 请假时长(小时)
     */
    function calculateLeaveDuration(options) {
        const {
            startTime,
            endTime,
            workStartTime = '08:30',
            workEndTime = '17:30',
            restStartTime = '12:00',
            restEndTime = '12:00',
            workdays = [1, 2, 3, 4, 5],
            excludeHolidays = [],
        } = options;

        // 无开始时间/结束时间/开始时间大于结束时间 返回0小时
        if (!startTime || !endTime || startTime >= endTime) return 0

        // 把请假时段处理成数组 每一项表示每一天的请假时间
        let leaveDays = [] // { startTime: HH:mm, endTime: HH:mm, week: Number('周几'), date: YYYY-MM-DD}
        // 判断请假开始结束时间是不是同一天  去除掉上班下班以外的时间  超出上下班时间将会格式化为上下班时间
        if (moment(startTime).isSame(endTime, 'day')) {
            leaveDays.push({
                startTime: startTime.substring(11) < workStartTime ? workStartTime : startTime.substring(11),
                endTime: endTime.substring(11) > workEndTime ? workEndTime : endTime.substring(11),
                week: moment(startTime).day(), date: startTime.substring(0, 10)
            })
        } else {
            let dateCache = moment(startTime).add(1, 'days').format("YYYY-MM-DD")
            leaveDays.push({
                startTime: startTime.substring(11) < workStartTime ? workStartTime : startTime.substring(11), endTime: workEndTime,
                week: moment(startTime).day(), date: startTime.substring(0, 10)
            })
            while (dateCache < moment(endTime).format("YYYY-MM-DD")) {
                leaveDays.push({
                    startTime: workStartTime, endTime: workEndTime,
                    week: moment(dateCache).day(), date: dateCache
                })
                dateCache = moment(dateCache).add(1, 'days').format("YYYY-MM-DD")
            }
            leaveDays.push({
                startTime: workStartTime, endTime: endTime.substring(11) > workEndTime ? workEndTime : endTime.substring(11),
                week: moment(endTime).day(), date: endTime.substring(0, 10)
            })
        }
        // console.log(leaveDays); // 去除上下班以外的时间
        let removeWeekendHolidays = leaveDays.filter(item => workdays.includes(item.week) && !excludeHolidays.includes(item.date))
        // console.log(removeWeekendHolidays); // 去除工作日/节假日以外的时间

        // 去除午休时间
        const rest_start = moment(restStartTime, 'HH:mm');
        const rest_end = moment(restEndTime, 'HH:mm');
        const restDuration = moment.duration(rest_end.diff(rest_start)).asMinutes();
        
        removeWeekendHolidays.forEach(item => {

            const start_time = moment(item.startTime, 'HH:mm');
            const end_time = moment(item.endTime, 'HH:mm');
            let leaveDuration = moment.duration(end_time.diff(start_time)).asMinutes();

            if (start_time.isBefore(rest_end) && end_time.isAfter(rest_start)) {
                const intersectionStart = moment.max(start_time, rest_start);
                const intersectionEnd = moment.min(end_time, rest_end);
                const intersectionDuration = moment.duration(intersectionEnd.diff(intersectionStart)).asMinutes();

                leaveDuration -= intersectionDuration;
            }

            item.leaveHour = Math.max(leaveDuration / 60, 0); // 每一天的请假时长
        })
        // 返回请假时长
        return + removeWeekendHolidays.reduce((sum, item) => sum + Number(item.leaveHour || 0), 0).toFixed(2)
    }

    
    // example
    const options = {
        startTime: '', endTime: '',
        workStartTime: '08:30', workEndTime: '17:30',
        restStartTime: '12:00', restEndTime: '13:00',
        workdays: [1, 2, 3, 4, 5],
        excludeHolidays: ['2023-10-01', '2023-10-02', '2023-10-03', '2023-10-04', '2023-10-05']
    }
    options.startTime = `2023-07-07 08:30`
    options.endTime = `2023-07-07 17:30`

    console.log(`请假时长为${calculateLeaveDuration(options)}小时`);

</script>

</html>

Tips:注释不能完整的描述清楚代码的思路,仅供参考,有啥问题请反馈