$ npm install leave-days-calculator
複製代碼
import leaveDaysCalculator form 'leave-days-calculator'
複製代碼
const start = '2020-06-22 上午'
const end = '2020-06-24 下午'
let leaveDays = leaveDaysCalculator(start, end) // 3
複製代碼
時間的格式只支持: YYYY-MM-DD 上午/下午javascript
自從作了小程序外勤打卡需求後,緊接着繼續作請假審批流程的開發,在處理請假表單的時候,有個請假時長的展現。當用戶選擇了請假的開始時間和結束時間後,能夠自動推算出請假時長,聽上去需求很常規。可是,哈哈哈,產品要求全部請假都按照半天請,好比說:java
請假的開始時間是6月1號上午,結束是6月2號上午,並非結束時間減去開始時間那麼簡單。上午到上午的這種狀況,多了半天吶。😂😂😂npm
那麼問題來了,如何準確的計算請假時長?小程序
按照當前請假,非當前請假兩類計算,數組
若是是當天請假:函數
若是是隔天計算: 結束時間 - 開始時間 = gap工具
此方案的核心是須要準確的計算出gap,可使用第三方工具來處理。從計算量上來看,工做量比較小。優化
純手動計算,按照當天上下午,隔天上下午,隔月上下午,隔年上下午手動計算出請假時長。這個方案的開發時長比較長,在開發週期比較寬裕的狀況下我選擇了方案,由於我還很想知道具體是這麼計算的。給本身找點事幹,給枯燥的coding,增添點趣味。ui
基於開始時間和結束時間的格式都是 YYYY-MM-DD 上午/下午
。spa
圖一:流程圖
算起來有四種計算規則:
須要一些基礎工具函數,好比說:
業務公共方法:
如下是請假時長計算器的源碼,僅供參考。
/** * @Authors youxiaoxiao (gao0807@foxmail.com) * @Date: 2020-06-1 * @Last Modified by: youxiaoxiao * 請假時長計算器:(經過 (開始時間 + 結束時間)計算請假時長) */
/** * 是不是閏年 * @param {*} year */
function isLeapYear (year) {
return year % 100 !== 0 && year % 4 === 0 || year % 400 === 0
}
/** * 獲取每一年每個月的天數 * @param {*} year * @param {*} month */
function getMaxDay (year, month) {
year = parseFloat(year)
month = parseFloat(month)
if (month === 2) {
return isLeapYear(year) ? 29 : 28
}
return [4, 6, 9, 11].indexOf(month) >= 0 ? 30 : 31
}
// 去0
function trimZero (val) {
val = String(val)
val = val ? parseFloat(val.replace(/^0+/g, '')) : ''
val = val || 0
val = val + ''
return val
}
/** * 同一天請假 */
function sameDayLeave(startNoon, endNoon) {
let leaveDays = 0
if (startNoon === endNoon) {
leaveDays = 0.5
}
else if (startNoon === '上午' && endNoon === '下午') {
leaveDays = 1
}
else if (startNoon === '下午' && endNoon === '上午') {
console.log('您選擇的時間有誤')
}
return leaveDays
}
/** * 隔天請假 */
function nextDayLeave(startDay, endDay, startNoon, endNoon) {
let leaveDays = 0
if (startNoon === '上午' && endNoon === '上午') {
leaveDays = endDay - startDay + 0.5
}
else if (startNoon === '上午' && endNoon === '下午') {
leaveDays = endDay - startDay + 1
}
else if (startNoon === '下午' && endNoon === '上午') {
leaveDays = endDay - startDay
}
else if (startNoon === '下午' && endNoon === '下午') {
leaveDays = endDay - startDay + 0.5
}
return leaveDays
}
/** * 開始月份請假天數 跨月,年纔會用到的函數 */
function startMonthLeaveDays (startMonthAllDays, startDay, startNoon) {
let startMonthLeave = 0
if (startNoon === '上午') {
startMonthLeave = Number(startMonthAllDays) - Number(startDay) + 1
} else if (startNoon === '下午') {
startMonthLeave = Number(startMonthAllDays) - Number(startDay) + 0.5
}
return Number(startMonthLeave)
}
/** * 結束月的請假天數 跨月,年纔會用到的函數 */
function endMonthLeaveDays(endDay, endNoon) {
let endLeaveDays = 0
if (endNoon === '上午') {
endLeaveDays = endDay - 0.5
} else if (endNoon === '下午') {
endLeaveDays = endDay
}
return Number(endLeaveDays)
}
/** * 經過開始時間和結束時間,計算請假時長 * @param {*} start 【支持:格式 yyyy-mm-dd n】 * @param {*} end 【支持:格式 yyyy-mm-dd n】 */
export default (start, end) => {
if(!start || !end) return 0
const startArr = start.split(' ') // 開始時間
const endArr = end.split(' ') // 結束時間
const startDate = startArr[0] // 開始日期
const endDate = endArr[0] // 結束日期
const startDateArr = startDate.split('-') // 開始日期 數組化
const endDateArr = endDate.split('-') // 結束日期 數組化
const startYear = startDateArr[0] // 開始日期:年
const startMonth = startDateArr[1] // 開始日期:月
const startDay = startDateArr[2] // 開始日期:日
const startNoon = startArr[1] // 開始時間的上下午
const endYear = endDateArr[0] // 結束日期:年
const endMonth = endDateArr[1] // 結束日期:月
const endDay = endDateArr[2] // 結束日期:日
const endNoon = endArr[1] // 結束時間的上下午
// 開始月份的總天數
const startMonthAllDays = getMaxDay(startYear, startMonth)
/** * 中間月份的請假天數計算 */
function centerMonthsLeave() {
// 中間月份天數累加
let leaveDays = 0
let monthArr = [] // 月份數組
for(let i = Number(trimZero(startMonth)); i <= Number(trimZero(endMonth)); i++) {
monthArr.push(i)
}
let everyMonthDays = 0
if (monthArr.length > 2) {
monthArr.pop()
monthArr.shift()
monthArr.forEach(month => {
everyMonthDays = Number(everyMonthDays) + Number(getMaxDay(startYear, month))
})
}
return (Number(leaveDays) + Number(everyMonthDays)).toFixed(1)
}
/** * 開始月份和結束月份請假天數 相鄰月請假,或則跨月請假 */
function startEndMonthNext() {
// 開始月份請假天數計算
let startLeaveDays = startMonthLeaveDays(startMonthAllDays, startDay, startNoon)
// 結束月份請假天數計算
let endLeaveDays = endMonthLeaveDays(endDay, endNoon)
// 天數累加
return Number(startLeaveDays) + Number(endLeaveDays) || 0
}
/** * 開始年的請假天數計算 */
function startYearLeaveDays () {
// 開始月份天數計算
let startMonthDays = startMonthLeaveDays(startMonthAllDays, startDay, startNoon)
// 剩下月份的天數
let otherMonthDays = 0
for(let i = Number(trimZero(startMonth)) + 1; i <= 12; i++) {
otherMonthDays = Number(otherMonthDays) + Number(getMaxDay(startYear, i))
}
return Number(startMonthDays) + Number(otherMonthDays) || 0
}
/** * 結束年的請假天數計算 */
function endYearLeaveDays() {
let endYearDays = 0
// 結束月份計算
let endLeaveDays = endMonthLeaveDays(endDay, endNoon)
// 前幾個月份天數累加
for(let i = 1; i < trimZero(endMonth); i++) {
endYearDays = Number(endYearDays) + Number(getMaxDay(endYear, i))
}
return Number(endYearDays) + Number(endLeaveDays)
}
/** * 跨年,中間年假期計算 */
function centerYearsLeaveDays () {
let centerYear = 0
if(endYear - startYear > 1) {
let centerYears = []
for(let startYear; startYear < endYear; startYear++) {
centerYears.push(startYear)
}
centerYears.pop()
centerYears.shift()
centerYears.forEach(year => {
for(let month = 1; month <=12; month++) {
centerYear = centerYear + getMaxDay(year, month)
}
})
}
return centerYear
}
// 請假天數
let leaveAllDays = 0
// 是否同年
if (startYear === endYear) {
// 是否同月
if (startMonth === endMonth) {
// 是否同天
if (startDay === endDay) {
leaveAllDays = sameDayLeave(startNoon, endNoon)
// 同年 同月 隔天請假計算
} else if (startDay < endDay) {
leaveAllDays = nextDayLeave(startDay, endDay, startNoon, endNoon)
} else {
console.log('結束時間的天不對')
}
// 同年 不是同月
} else if (startMonth < endMonth) {
// 兩個月相鄰狀況, 開始月份剩餘天數,結束月份請假天數 之和
let startEndMonthLeaveDays = startEndMonthNext()
// 中間月份請假的天數
let centerMonthsDays = centerMonthsLeave()
// 請假天數彙總
leaveAllDays = Number(startEndMonthLeaveDays) + Number(centerMonthsDays)
} else {
console.log('結束時間的月份不對')
}
// 不是同年
} else if (startYear < endYear) {
// 開始年的請假天數計算: 開始月剩下的天數 + 剩下月份的天數
let startYearDays = startYearLeaveDays()
// 結束年的請假天數計算: 結束月的天數 + 結束月以前月份的天數
let endYearDays = endYearLeaveDays()
// 中間年份的天數
let centerYear = centerYearsLeaveDays()
// 請假天數彙總累加
leaveAllDays = Number(startYearDays) + Number(endYearDays) + Number(centerYear)
} else {
console.log('結束時間的年份不對')
}
// console.log(leaveAllDays)s
return leaveAllDays
}
複製代碼
一個請假時長計算器就開發完了,其實方案一更省事一點,方案二的實現,還有不少能夠優化的點。最終封裝好的請假時長計算器 npm包:leave-days-calculator。
若是你有其它的方案或者優化實現,歡迎在下方留言交流。