一、前端开发-JS请假时间计算

1、前言

        计算请假时间还是蛮考虑逻辑的,可以借鉴借鉴我的,有啥需要改进的记得留言。

2、代码

2.1 html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
		<title>计算请假时间</title>
		<script src="js/jquery-3.6.1.min.js"></script>
		<script src="js/qingjia/xxyLeaveTimeCount.js"></script>
	</head>
	<style>
		.mt-10{
			margin-top: 10px;
		}
	</style>
	<body>
		<div>
			<h2>请假时间</h2>
			<div>
				<div>开始时间:</div>
				<div><input id="startTime" name="startTime" value="2023-09-04 08:30:00"/></div>
			</div>
			<div class="mt-10">
				<div>结束时间:</div>
				<div><input id="endTime" name="endTime" value="2023-09-04 18:00:00"/></div>
			</div>
			<div class="mt-10">
				<div>请假类型:</div>
				<div>
					<select id="vacateType" name="vacateType">
						<option value="">请选择</option>
						<option value="1">事假</option>
						<option value="2">病假</option>
						<option value="3">补休</option>
						<option value="4">丧假</option>
						<option value="5">产假</option>
						<option value="6">年休假</option>
						<option value="8">婚假</option>
						<option value="9">生日假</option>
					</select>
				</div>
				
			</div>
			<div class="mt-10">
				<div>休息日请假(勾选后请假时长会包括休息日,请假的时间也不限制):</div>
				<div>
					<input type="radio" title="是" value="true" name="isMakeUpForWork"/> 是
					<input type="radio" title="否" value="false" name="isMakeUpForWork" checked/> 否
				</div>
				
			</div>
			<div class="mt-10">
				<button id="submit">计算</button>
			</div>
			
			<div class="mt-10">
				<input id="totalLeaveHours" placeholder="请假总时长"/>
			</div>
		</div>
		
	</body>
	<script>
		
		$(function(){
			$("#submit").click(function(){
				var  startTime=$("#startTime").val();
				var  endTime=$("#endTime").val();
				var  vacateType=$("#vacateType").val();
				if(!vacateType){
					alert("请选择请假类型")
					return;
				}
				var  isMakeUpForWork=$("input[name='isMakeUpForWork']:checked").val();
				//周末也计算到内
				var totalLeaveHours=getLeaveHours(startTime,endTime,vacateType,isMakeUpForWork);
				$("#totalLeaveHours").val(totalLeaveHours);
			})
		})
		
	</script>
</html>

2.2 js

/**
 * 计算请假时长工具类
 */
/**
 * 计算所用常量
 */
const countConst={
    "workHours":7,//每天的工作时长
    "noonStartBreakTime":12,//午休开始时间 12:00
    "noonEndBreakTime":14.5,//午休结束时间 14:30
    "workStartTime":8.5,//上班时间 8:30
    "workEndTime":18,//下班时间 18:00
    "morningHours":3.5,//上午上班时长
    "afternoonHours":3.5,//下午上班时长
    "noonHours":2.5//午休总时长
};
/**
 * 计算请假时长
 * @param {string} start 请假开始时间 格式 2023-01-01 08:00:00
 * @param {string} end 请假结束时间
 * @param {string} vacateType 请假类型
 * @param {string} isMakeUpForWork 是否补班时段请假,true才能选择休息日请假
 */
function getLeaveHours(start,end,vacateType,isMakeUpForWork){
    console.log(start);
    console.log(end);
    //请假总时长
    let totalDurationLeave=0;
    //请假开始和结束时间必须在8:30-12:00或14:30-18:00里面
    var startTime = new Date(start.replace(/-/g, '/'));
    var	endTime = new Date(end.replace(/-/g, '/'));

    //验证请假时间是否符合
    if(!verifyTime(startTime,vacateType,isMakeUpForWork) || !verifyTime(endTime,vacateType,isMakeUpForWork)){
        // alert("请假时间必须在8:30-12:00或14:30-18:00");
        return 0;
    }
    if(endTime.getTime()<startTime.getTime()){
        alert("开始时间必须小于结束时间!");
        return 0;
    }
    //两时间的毫秒差
    let ms = Math.abs(endTime.getTime() - startTime.getTime());
    // console.log("毫秒差="+ms);
    //相差时长
    let subtractionHours=accDiv(ms,1000*60*60);
    // console.log("时间差="+subtractionHours);
    if(subtractionHours<2){
        alert("请假时长至少两小时!");
        return 0;
    }
    //需要减去的午休总时长
    let subtractNoonHours=0;

    //开始时间的几号
    let startDay=startTime.getDate();
    // console.log("startDay",startDay);
    //结束时间的几号
    let endDay=endTime.getDate();
    // console.log("endDay",endDay);
    //开始时间的小时
    let startHours=startTime.getHours();
    //结束时间的小时
    let endHours=endTime.getHours();
    //开始时间的分钟
    let startMinutes=startTime.getMinutes();
    //结束时间的分钟
    let endMinutes=endTime.getMinutes();
    //日期差
    let subtractDay=endDay-startDay;
    //请1天及以内
    if(subtractionHours<24 && subtractDay==0){
        //这属于跨午休了
        if(startHours<=12&&endHours>=14){
            subtractNoonHours=countConst.noonHours;
        }
        totalDurationLeave=accSub(subtractionHours,subtractNoonHours);
        return totalDurationLeave;
    }else{//请1天以上
        //请假天数=日期差+1;
        let day=accAdd(subtractDay,1);
        // console.log("day===");
        // console.log(day);
        /**
         * 计算第一天请假时长
         */
            //分钟转换成小时
        var minutesToHours=accDiv(startMinutes,60);
        // console.log("转换分钟:"+minutesToHours);
        //请假小时数 例如:8:30为8.5
        let morningH=accAdd(startHours,minutesToHours);
        // console.log("请假小时:"+morningH);
        //第一天请假时长
        let oneDayLeaveHours=getOneDayLeaveDuration(startHours,morningH);
        // console.log("第一天请假时长:"+oneDayLeaveHours);
        /**
         * 计算最后一天请假时长
         */
            //分钟转换成小时
        var endMinutesToHours=accDiv(endMinutes,60);
        // console.log("转换分钟:"+endMinutesToHours);
        //上午请假时长
        let endMorningH=accAdd(endHours,endMinutesToHours);
        //请假小时数 例如:8:30为8.5
        // console.log("请假小时:"+endMorningH);
        //最后一天请假时长
        let endDayLeaveHours=getEndDayLeaveDuration(endHours,endMorningH);
        // console.log("最后一天请假时长:"+endDayLeaveHours);

        //中间跨的天数=(总跨天数-前后天数(2天))*每天工作时长
        let daySpan=accSub(day,2);
        daySpan=accMul(daySpan,countConst.workHours);
        //请假总时长=第一天请假时长+(总跨天数-2)*每天工作时长+最后一天请假时长
        totalDurationLeave=accAdd(oneDayLeaveHours,endDayLeaveHours);
        totalDurationLeave=accAdd(totalDurationLeave,daySpan);
        /**
         * 只有产假会把星期天和星期六算进去
         * 周末排除
         *
         */
        if(vacateType!='5' && isMakeUpForWork=="false"){
            let restDay=weekendBetween(start,end);
            // console.log("其中休息日的天数");
            // console.log(restDay);
            //休息日大于0 不是产假
            if(restDay>0){
                //实际请假总时长=请假总时长-(休息日*每天工作时长)
                let restDayTime=accMul(restDay,countConst.workHours);
                totalDurationLeave=accSub(totalDurationLeave,restDayTime);
            }

        }

        return totalDurationLeave;
    }
}
/**
 * 判断请假时间里面有多少个周末
 */
// console.log("09-04~10-20");
// console.log(weekendBetween("2023-09-01 08:30:00","2023-10-20 18:00:00"));

function weekendBetween(dtStart, dtEnd) {
    //休息日
    let tRestDay=0;
    /**
     * 时间处理,把时分秒设为一致的,方便计算
     */
    var dataStartRest=dtStart.split(" ");
    var restStartDate=dataStartRest[0];
    var dataEndRest=dtEnd.split(" ");
    var restEndDate=dataEndRest[0];
    var restStartDateStr=restStartDate+" 08:00:00";
    var restEndDateStr=restEndDate+" 08:00:00";
    var startTime = new Date(restStartDateStr.replace(/-/g, '/'));
    var endTime = new Date(restEndDateStr.replace(/-/g, '/'));
    /**
     * 获取时间的各种值
     */
        //星期
    let dayStart=startTime.getDay();
    let dayEnd=endTime.getDay();
    //日期
    let dateStart=startTime.getDate();
    let dateEnd=endTime.getDate();
    //一个小时的毫秒数
    let hoursMs=1000*60*60;
    //一天的毫秒数
    let dayMs=hoursMs*24;
    //日期转为毫秒
    let timeStart=startTime.getTime();
    let timeEnd=endTime.getTime();
    //两时间的毫秒差
    let ms = Math.abs(endTime.getTime() - startTime.getTime());
    //间隔小时
    let intervalHours = accDiv(ms,hoursMs);
    //间隔天数
    let intervalDay = accDiv(ms,dayMs);
    let dateTimeStr=endTime.getTime();
    var dateTime="";
    //计算间隔中有多少休息日
    for (var i = 0; i < intervalDay; i++) {
        //第一次以默认值计算
        if(i!=0){
            dateTimeStr=accSub(dateTimeStr,dayMs);
        }
        dateTime=getSpeTime(dateTimeStr);
        var dateNowTime = new Date(dateTime.replace(/-/g, '/'));
        if(dateNowTime.getDay()==6||dateNowTime.getDay()==0){
            // console.log(dateTime);
            tRestDay++;
        }

    }
    return tRestDay;
}
function getSpeTime(timeStr) {
    var dateSpe = new Date(parseInt(timeStr));
    // console.log("dateSpe====")
    // console.log(dateSpe)
    // timeStr是毫秒值
    // 获取年份
    var year=dateSpe.getFullYear();
    //获取月份,获取的月份比实际小1,所以需要+1
    var month=dateSpe.getMonth()+1;
    if (month < 10) {
        month = '0' + month
    }
    //获取日
    var date=dateSpe.getDate();
    if (date < 10) {
        date = '0' + date
    }
    //获取时
    var hours=dateSpe.getHours();
    if (hours < 10) {
        hours = '0' + hours
    }
    //获取分
    var minutes=dateSpe.getMinutes();
    if (minutes < 10) {
        minutes = '0' + minutes
    }
    //获取秒
    var seconds=dateSpe.getSeconds();
    if (seconds < 10) {
        seconds = '0' + seconds
    }

    //组合格式为年-月-日 时:分:秒(2022-6-6 12:12:12)
    return year+"-"+month+"-"+date+" "+hours+":"+minutes+":"+seconds;
}
/**
 * 毫秒数转换成日期格式
 * @param {Object} milliseconds
 */
function convertMillisecondsToDate(milliseconds) {
    const date = new Date(milliseconds);
    const year = date.getFullYear();
    const month = date.getMonth() + 1;
    const day = date.getDate();
    const hours = date.getHours();
    const minutes = date.getMinutes();
    const seconds = date.getSeconds();

    let dateString = `${year}-${month < 10 ? '0' + month : month}-${day < 10 ? '0' + day : day} ${hours < 10 ? '0' + hours : hours}:${minutes < 10 ? '0' + minutes : minutes}:${seconds < 10 ? '0' + seconds : seconds}`;

    return dateString;
}
/**
 * 获取第一天请假时长
 * @param {Object} hours 请假的小时 例如:8:30记作8
 * @param {Object} realityLeaveHours 实际请假的小时 例如:8:30记作8.5
 */
function getOneDayLeaveDuration(hours,realityLeaveHours){
    //上午或下午请假时长
    let noeMorningHours=0;
    //请假实际时长
    let leaveHours=0;
    //判断请假时间是上午还是下午
    //请假时间<=上午下班时间 是上午请假
    if(hours<=countConst.noonStartBreakTime){
        //用上午下班时间-实际请假的小时=早上请假时长
        noeMorningHours=accSub(countConst.noonStartBreakTime,realityLeaveHours);
        //第一天请假时长=下午工作时长+早上请假时长
        leaveHours=accAdd(countConst.afternoonHours,noeMorningHours);
    }else{//下午请假
        //下午请假时长=下午下班时间-实际请假的小时
        noeMorningHours=accSub(countConst.workEndTime,realityLeaveHours);
        //第一天请假时长=下午请假时长
        leaveHours=noeMorningHours;
    }
    return leaveHours;
}
/**
 * 获取最后一天请假时长
 * @param {Object} hours 请假的小时 例如:8:30记作8
 * @param {Object} realityLeaveHours 实际请假的小时 例如:8:30记作8.5
 */
function getEndDayLeaveDuration(hours,realityLeaveHours){
    //上午或下午请假时长
    let noeMorningHours=0;
    //请假实际时长
    let leaveHours=0;
    //判断请假时间是上午还是下午
    //请假时间<=上午下班时间 是上午请假
    if(hours<=countConst.noonStartBreakTime){
        //早上请假时长=请假小时-早上上班时间
        noeMorningHours=accSub(realityLeaveHours,countConst.workStartTime);
        //最后一天请假时长=早上请假时长
        leaveHours=noeMorningHours;
    }else{//下午请假
        //下午请假时长=实际请假的小时-下午上班时间
        noeMorningHours=accSub(realityLeaveHours,countConst.noonEndBreakTime);
        //最后一天请假时长=下午请假时长+上午工作小时(3.5小时)
        leaveHours=accAdd(noeMorningHours,countConst.morningHours);
    }
    return leaveHours;
}
/**
 * 验证请假时间是否在工作时间段
 * @param {Object} time 请假时间
 */
function verifyTime(time,vacateType,isMakeUpForWork){
    //小时
    let tHours=time.getHours();
    //分钟
    let tMinutes=time.getMinutes();
    //分钟转换成小时
    let minutesToHours=accDiv(tMinutes,60);
    //请假小时数 例如:8:30为8.5
    let leaveH=accAdd(tHours,minutesToHours);
    //请假时间是否在工作时间
    var isWorkTime=true;
    //不在工作时间
    if(leaveH<countConst.workStartTime||leaveH>countConst.workEndTime){
        alert("请假时间必须在8:30-12:00或14:30-18:00!")
        isWorkTime=false;
    }
    if (time.getSeconds()!=0) {
        alert("为了更准确的计算请假时长,请假时间的秒数请设置为00!")
        isWorkTime=false;
    }
    //不是产假的要判断请假时间不能选择星期六、星期天
    // console.log("vacateType====")
    // console.log(vacateType)
    // console.log(isMakeUpForWork)
    if(vacateType!='5' && isMakeUpForWork=="false"){
        if (time.getDay()==6||time.getDay()==0) {
            alert("请假时间不能选休息日(产假或勾选休息日请假除外)!")
            isWorkTime=false;
        }
    }

    //处于午休时间段
    if(leaveH>countConst.noonStartBreakTime && leaveH<countConst.noonEndBreakTime){
        // console.log("处于午休时间段");
        isWorkTime=false;
    }
    // console.log("请假时间是否符合:"+isWorkTime);
    return isWorkTime;
}


/**
 ** 加法函数,用来得到精确的加法结果
 ** 说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显。这个函数返回较为精确的加法结果。
 ** 调用:accAdd(arg1,arg2)
 ** 返回值:arg1加上arg2的精确结果
 **/
function accAdd(arg1, arg2) {
    var r1, r2, m, c;
    try {
        r1 = arg1.toString().split(".")[1].length;
    }
    catch (e) {
        r1 = 0;
    }
    try {
        r2 = arg2.toString().split(".")[1].length;
    }
    catch (e) {
        r2 = 0;
    }
    c = Math.abs(r1 - r2);
    m = Math.pow(10, Math.max(r1, r2));
    if (c > 0) {
        var cm = Math.pow(10, c);
        if (r1 > r2) {
            arg1 = Number(arg1.toString().replace(".", ""));
            arg2 = Number(arg2.toString().replace(".", "")) * cm;
        } else {
            arg1 = Number(arg1.toString().replace(".", "")) * cm;
            arg2 = Number(arg2.toString().replace(".", ""));
        }
    } else {
        arg1 = Number(arg1.toString().replace(".", ""));
        arg2 = Number(arg2.toString().replace(".", ""));
    }
    return (arg1 + arg2) / m;
}

/**
 ** 减法函数,用来得到精确的减法结果
 ** 说明:javascript的减法结果会有误差,在两个浮点数相减的时候会比较明显。这个函数返回较为精确的减法结果。
 ** 调用:accSub(arg1,arg2)
 ** 返回值:arg1减去arg2的精确结果
 **/
function accSub(arg1, arg2) {
    var r1, r2, m, n;
    try {
        r1 = arg1.toString().split(".")[1].length;
    }
    catch (e) {
        r1 = 0;
    }
    try {
        r2 = arg2.toString().split(".")[1].length;
    }
    catch (e) {
        r2 = 0;
    }
    m = Math.pow(10, Math.max(r1, r2)); //last modify by deeka //动态控制精度长度
    n = (r1 >= r2) ? r1 : r2;
    return ((arg1 * m - arg2 * m) / m).toFixed(n);
}

/**
 ** 乘法函数,用来得到精确的乘法结果
 ** 说明:javascript的乘法结果会有误差,在两个浮点数相乘的时候会比较明显。这个函数返回较为精确的乘法结果。
 ** 调用:accMul(arg1,arg2)
 ** 返回值:arg1乘以 arg2的精确结果
 **/
function accMul(arg1, arg2) {
    var m = 0, s1 = arg1.toString(), s2 = arg2.toString();
    try {
        m += s1.split(".")[1].length;
    }
    catch (e) {
    }
    try {
        m += s2.split(".")[1].length;
    }
    catch (e) {
    }
    return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m);
}

/**
 ** 除法函数,用来得到精确的除法结果
 ** 说明:javascript的除法结果会有误差,在两个浮点数相除的时候会比较明显。这个函数返回较为精确的除法结果。
 ** 调用:accDiv(arg1,arg2)
 ** 返回值:arg1除以arg2的精确结果
 **/
function accDiv(arg1, arg2) {
    var t1 = 0, t2 = 0, r1, r2;
    try {
        t1 = arg1.toString().split(".")[1].length;
    }
    catch (e) {
    }
    try {
        t2 = arg2.toString().split(".")[1].length;
    }
    catch (e) {
    }
    with (Math) {
        r1 = Number(arg1.toString().replace(".", ""));
        r2 = Number(arg2.toString().replace(".", ""));
        return (r1 / r2) * pow(10, t2 - t1);
    }
}

3、界面

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值