共计 2023 个字符,预计需要花费 6 分钟才能阅读完成。
近日,接到个紧急需求,考勤员给员工排班,但是这个员工当天有请假时间段,有休息时间段,有用餐时间段。所以这个员工当天的排班时长应该是 时长 = 班别时长 - 请假时长 - 用餐时长 - 休息时长
。
针对这个需求,我们有这样一批数据:
var schedule = { | |
beginTime: '2019-05-24 20:00', | |
endTime: '2019-05-25 07:00' | |
} | |
var leaveTime = [{ | |
beginTime: '2019-05-24 18:00', | |
endTime: '2019-05-25 00:00' | |
}] | |
var mealTime = [{ | |
beginTime: '2019-05-24 23:00', | |
endTime: '2019-05-25 01:00' | |
}] | |
var breakTime = [{ | |
beginTime: '2019-05-25 00:00', | |
endTime: '2019-05-25 02:00' | |
}, { | |
beginTime: '2019-05-25 04:00', | |
endTime: '2019-05-25 06:00' | |
}] |
由于请假、用餐时间段可以在排班区间外 (???? 不要问为什么可以,这是需求️),所以我们对于请假和用餐必须要先处理一次。我们首先分析一下,这里用请假举例。
- 假如班 8 ~ 18,请假 12 ~ 15,那么这段请假是有效的
- 假如班 8 ~ 18,请假 7 ~ 10,那么请假的有效时段为 8 ~ 10
- 假如班 8 ~ 18,请假 15 ~ 20,那么请假的有效时段为 15 ~ 18
针对以上结论,代码逻辑如下:
function getExceptTimePeriodInSchedule(schedule, timePeriod){ | |
const BT = schedule.beginTime; | |
const ET = schedule.endTime; | |
let exceptTimePeriod = []; | |
_.each(timePeriod, timeRange=>{let { beginTime, endTime} = timeRange; | |
if(beginTime < BT && endTime >= BT && endTime < ET){ | |
exceptTimePeriod.push({ | |
beginTime: BT, | |
endTime | |
}); | |
}else if(beginTime >= BT && beginTime < ET && endTime <= ET){ | |
exceptTimePeriod.push({ | |
beginTime, | |
endTime | |
}); | |
}else if(beginTime >= BT && beginTime < ET && endTime > ET){ | |
exceptTimePeriod.push({ | |
beginTime, | |
endTime: ET | |
}); | |
}else if(beginTime < BT && endTime > ET){ | |
exceptTimePeriod.push({ | |
beginTime: BT, | |
endTime: ET | |
}); | |
} | |
}) | |
return exceptTimePeriod; | |
} |
根据 getExceptTimePeriodInSchedule 方法,我们已经获取到所有在排班区间内的排班数据。这个时候,我们就需要处理请假、休息、用餐交叉问题。看见三个数组,想想都有点发慌,首先脑海中瞬间决定不能通过遍历每一个数组来解决交叉问题。我们先画个图再仔细思考。
- 请假、休息、用餐是无顺序的,首先需要对请假、休息、用餐按照升序进行排序,对于开始时间相同的,按照结束时间升序。
- 请假、休息、用餐各有一个数组,不好处理,我们把他们合并成一个数组,这样我们面对的问题就是一个数组的交叉重复。
- 单个数组去重,我们知道有
filter
、Set
和reduce
等方法,如果不知道的可以看 How to Remove Array Duplicates in ES6。针对于我们遇到的难点,我们打算用reduce
来解决。
对应代码如下:
function getExceptTimePeriod(timePeriod){timePeriod = _.sortBy(timePeriod, ['beginTime', 'endTime']); | |
timePeriod = _.reduce( | |
timePeriod, | |
(result, item) => {let last = result[result.length - 1]; | |
if (last) { | |
if (item.beginTime <= last.endTime && | |
item.beginTime >= last.beginTime && | |
item.endTime > last.endTime) {last.endTime = item.endTime;} else {result.push(item); | |
} | |
return result; | |
} else {result.push(item); | |
return result; | |
} | |
}, | |
[]); | |
return timePeriod; | |
}; |
通过上面两个关键方法,我们就可以获取到不交叉重复的时间区间。欢迎小伙伴提出改进和其他解决方案,如果觉得这篇文章对你有所帮助,还请多多支持 ????。
正文完
发表至: javascript
2019-05-29