轉載請註明本文地址:https://www.cnblogs.com/qiaoge0923/p/10219155.html 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
計算兩個時間差的小時數:this
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
不一樣單位對請假的限制條件不一樣,現規定請假天數計算規則以下:spa
一、請假半天記0.5天;3d
二、小於半天部分,1小時計0.1天,2小時計0.2天,以此類推code
那麼計算邏輯也還比較簡單:orm
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