转载请注明本文地址:https://www.cnblogs.com/qiaoge0923/p/10219155.html
计算请假天数,笼统来说就是计算两个日期的差值。对于JS来说,两个时间直接相减,得到的是这两个时间差的毫秒数。
先上代码后贴图。
后文中用到的测试数据如下:
var dateStart = ‘2018-12-01 04:15‘, dateEnd = ‘2018-12-08 12:15‘;
var MS_HOUR = 1000*60*60;
普通计算两个时间差的方法如下:
function getDiff(start, end) { var s = Date.parse(start), e = Date.parse(end); //取绝对值 return Math.abs(e - s); } console.log(getDiff(dateStart, dateEnd)); 输出: 633600000
计算两个时间差的小时数:
function getDiffByHour(start, end) { /**** * start:请假开始时间 * end:请假结束时间 * 计算小时数(1位小数) * ***/ var s = Date.parse(start), e = Date.parse(end); //取绝对值 var diff = Math.abs(e - s); return (diff / (1000 * 60 * 60)).toFixed(1); } console.log(getDiffByHour(dateStart, dateEnd)); 输出: 176.0
不同单位对请假的限制条件不同,现规定请假天数计算规则如下:
1、请假半天记0.5天;
2、小于半天部分,1小时计0.1天,2小时计0.2天,以此类推
那么计算逻辑也还比较简单:
function getDiffByDay(start, end) { /**** * start:请假开始时间 * end:请假结束时间 * 计算天数,半天按0.5天计算,小于半天,1小时计0.1天,2小时计0.2天,3小时计0.3天,4小时计0.4天(1位小数) * ***/ var s = Date.parse(start), e = Date.parse(end); //取绝对值 var diff = Math.abs(e - s); var result = 0, hour = Math.floor(diff / (1000 * 60 * 60)), day = Math.floor(diff / (1000 * 60 * 60 * 24)); result = day; if (day > 0) { //去掉天数部分,仅留小时数 hour -= day * 24; } if (hour > 5) { //如果大于半天(5小时) result += 0.5; hour = Math.floor((diff - (day * 24 + 5) * 1000 * 60 * 60) / (1000 * 60 * 60)); } if (hour > 1) { result += hour * 0.1; } return result; } console.log(getDiffByDay(dateStart, dateEnd)); 输出: 7.8
倘若规定上下班时间,中午休息时间,工作时长等等,那计算的逻辑就相当复杂了。
现规定上下班及午休时间如下:
上班时间:8:00
下班时间:18:00
午休时间:12:00-14:00
(正常日工作时长:8小时)
那么,请假1小时则为1/8天,4小时即为0.5天。
简单分析:
1.请假时段在同一天内,直接计算;
2.请假时段跨越了多天的情况,我们可以把请假时间分成两个部分,请假时间 start 至 end,可以看成第一部分: start的时间起到第二天 end时间止的请假时长,第二部分:start日期与end日期之间的天数(不含start和end)。
例如:请假时段 ‘2018-01-01 8:00’ 至 ‘2018-01-03 12:00‘,那么请假时长可以分为 ‘2018-01-01 8:00‘至‘2018-01-02 12:00‘的时长(过滤闲暇时间和午休时间),和‘2018-01-01‘至‘2018-01-03‘间的天数,即为 1.5+1=2.5天。
这种情况下,直接是end-start然后除去午休时间,最后得到的小时数来计算天数。
function getLeaveDayInOneDay(start, end, wt) { /** * 获取一天内的请假天数 * @start:起始时间 * @end:截止时间 * @wt:作息时间,包含上下班时间和午休时间 * */ var diff = { }; diff.d = 0; /** * diff: * { * d:天数 * h:小时数 * st:起始时间毫秒数 * et:截止时间毫秒数 * } * */ try { var startInt = Date.parse(start), endInt = Date.parse(end); if (startInt <= wt.on && wt.off <= endInt) { //全天 diff.d = 1.0; } else if (startInt <= wt.on && wt.noonOn <= endInt && endInt <= wt.noonOff) { //上半天 diff.d = 0.5; } else if (wt.noonOn <= startInt && startInt <= wt.noonOff && wt.off <= endInt) { //下半天 diff.d = 0.5; } else { //去除极端情况,确保请假时间在工作时间内 diff.st = Math.max(wt.on, startInt); //取上班时间内 diff.st = diff.st <= wt.noonOn ? diff.st : (wt.noonOff <= diff.st ? diff.st : wt.noonOff && wt.on != endInt); diff.st = Math.min(diff.st, wt.off); //取下班时间内 diff.et = Math.max(diff.st, endInt); diff.et = Math.min(diff.et, wt.off); diff.et = diff.et <= wt.noonOn ? diff.et : (wt.noonOff <= diff.et ? diff.et : wt.noonOn && startInt != wt.off); diff.et = Math.max(wt.on, diff.et); diff.diff = diff.et - diff.st; if (diff.st <= wt.noonOn && wt.noonOff <= diff.et) { //去除午休时段 diff.diff = diff.diff - (wt.noonOff - wt.noonOn); } diff.h = diff.diff / MS_HOUR; //TODO:根据小时数计算天数 diff.d += getLeaveByHour(diff.h, wt.wh); } } catch (e) { this.log("计算【" + start + "】到【" + end + "】期间的请假天数发生异常:" + e.message); }return diff.d; };
计算第一部分的时长:
function getLeaveDaysInTwoDay(start, end, wtObjStr) { /** * 获取start到第二天end时间内的请假时长 * @start:起始时间 * @end:截止时间 * @wtObjStr:作息时间,包含上下班时间和午休时间 * { * wh:日工作时长,整型,如8 * on:上班时间,字符串,如‘09:00‘ * off:下班时间,字符串,如‘18:00‘ * noonOn:中午开始时间,字符串,如‘12:00‘ * noonOff:中午结束时间,字符串,如‘14:00‘ * } * 值得注意的是,如果未设置作息时间,则上班时间为00:00,下班时间为23:59,中午时间均为下班时间,这个应该在setWorkTime中进行设置 * */ var wt = { }, _date = ‘2019-01-08‘, _date2 = ‘2019-01-09‘; var start = Date.parse(_date + ‘ ‘ + start.Format(‘hh:mm:ss‘)), end = Date.parse(_date2 + ‘ ‘ + end.Format(‘hh:mm:ss‘)); wt.wh = wtObjStr.wh; wt.on = Date.parse(_date + ‘ ‘ + wtObjStr.on); wt.off = Date.parse(_date + ‘ ‘ + wtObjStr.off); wt.noonOn = Date.parse(_date + ‘ ‘ + wtObjStr.noonOn); wt.noonOff = Date.parse(_date + ‘ ‘ + wtObjStr.noonOff); wt.on2 = Date.parse(_date2 + ‘ ‘ + wtObjStr.on); wt.off2 = Date.parse(_date2 + ‘ ‘ + wtObjStr.off); wt.noonOn2 = Date.parse(_date2 + ‘ ‘ + wtObjStr.noonOn); wt.noonOff2 = Date.parse(_date2 + ‘ ‘ + wtObjStr.noonOff); var diff = 0; start = Math.max(start, wt.on); start = start <= wt.noonOn ? start : (wt.noonOff < start ? start : wt.noonOff); start = Math.min(start, wt.off); end = Math.max(end, wt.on2); end = end <= wt.noonOn2 ? end : (wt.noonOff2 < end ? end : wt.noonOn2); end = Math.min(end, wt.off2); diff = wt.off - start; if (start <= wt.noonOn) diff -= (wt.noonOff - wt.noonOn); diff += (end - wt.on2); if (end >= wt.noonOff2) diff -= (wt.noonOff2 - wt.noonOn2); return getLeaveByHour(diff / MS_HOUR, wt.wh); };
再来看第二部分,先笼统计算一下天数:
function getDaysOfPeriod(start, end) { /** * 获取一段时期内的天数,包含起止日期 * @start:起始时间 * @end:截止时间 * */ try { var startObj = { ‘y‘: start.getFullYear(), ‘m‘: start.getMonth() + 1, ‘d‘: start.getDate() }, endObj = { ‘y‘: end.getFullYear(), ‘m‘: end.getMonth() + 1, ‘d‘: end.getDate() }; //start和end必须包含,所以需要+1 var startPart = start.getTotalDaysOfMonth() - startObj.d + 1, monthPart = 0, endPart = endObj.d; if (startObj.y != endObj.y) { //跨年的情况 var startMonths = 12 - startObj.m; //获取start年份中剩下的月份数 for (var i = startObj.m + 1; i <= startObj.m + startMonths; i++) { monthPart += (new Date(startObj.y, i - 1, 1)).getTotalDaysOfMonth(); } for (var i = 1; i <= endObj.m - 1; i++) { monthPart += (new Date(endObj.y, i - 1, 1)).getTotalDaysOfMonth(); } } else { if (startObj.m != endObj.m) { //跨月 for (var i = startObj.m + 1; i < endObj.m; i++) { monthPart += (new Date(startObj.y, i - 1, 1)).getTotalDaysOfMonth(); } } else { startPart = 0; endPart = endObj.d - startObj.d + 1; } } this.log("【" + start + "】到【" + end + "】期间的天数:" + (startPart + monthPart + endPart)); return startPart + monthPart + endPart; } catch(e) { this.log("计算【" + start + "】到【" + end + "】期间的天数发生异常:" + e.message); return 0; } };
这个天数除去起止日期即为第二部分。
主函数如下:
function getLeaveDays(start, end) { /** * 获取一段时间内的请假天数,包含上下班时间和午休时间 * @start:起始时间 * @end:截止时间 * */ var startInt = Date.parse(start), endInt = Date.parse(end), startObj = { ‘y‘: start.getFullYear(), ‘m‘: start.getMonth() + 1, ‘d‘: start.getDate(), ‘h‘: start.getHours(), ‘mi‘: start.getMinutes() }, endObj = { ‘y‘: end.getFullYear(), ‘m‘: end.getMonth() + 1, ‘d‘: end.getDate(), ‘h‘: end.getHours(), ‘mi‘: end.getMinutes() }; var diff = 0,wt = { }, _date = start.Format(‘yyyy-MM-dd‘); wt.wh = this._work.wh; wt.on = Date.parse(_date + ‘ ‘ + this._work.on); wt.off = Date.parse(_date + ‘ ‘ + this._work.off); wt.noonOn = Date.parse(_date + ‘ ‘ + this._work.noonOn); wt.noonOff = Date.parse(_date + ‘ ‘ + this._work.noonOff); //请假起止时间不在同一日期 if(startObj.y !== endObj.y || startObj.m !== endObj.m || startObj.d !== endObj.d) { var days = getDaysOfPeriod(start, end); /** * days包含start和end,days>=2,所以请假时间可以按两个部分计算: * start那天到第二天end时间的请假时长+start和end中间天数 */ if (days < 2) { this.log(‘计算一段时间内(非同一天)的天数不能少于2‘); return 0; } diff += days - 2; diff += getLeaveDaysInTwoDay(start, end, this._work); } else { //请假起止时间在同一日期内 diff = getLeaveDayInOneDay(start, end, wt); } return diff; };
function getLeaveByHour(hour, workLen) { var diff = 0; var dv = Math.floor(hour / workLen); if (dv >= 1) { diff += dv; hour -= dv * workLen; } if (hour >= workLen / 2) { diff += 0.5; hour -= workLen / 2; } if (hour >= 1) { diff += parseFloat((hour / workLen).toFixed(1)); } return diff; };
再贴上测试效果吧:
当然,小数点后面的四舍五入的处理就看各自的情况了。
花了点时间整理封装了下,不知道怎么上传附件,有需要源码的可以留言。
对于请假天数的计算就写这么些了,不同场景肯定有不同的需求,以上算法只是抛砖引玉,更多的还需要自行修改,你也可以留言一起学习。
小菜一枚,大神路过请多多指教,诚谢。
转发请注明出处。
最后编辑时间:2019-01-10
原文:https://www.cnblogs.com/qiaoge0923/p/10219155.html