如何定义TimeFold员工排班的unavailableEmployee约束(含时间范围)
问题
我想要复现TimeFold官方员工排班子项目的功能,但我的场景中员工可用性包含起止日期范围,而非单一日期。示例中仅对比班次开始日期与可用性日期,我需修改unavailableEmployee约束,判断班次是否处于员工可用性范围内,并按可用性类型调整评分,请问正确实现方式是什么?
原示例代码如下:
Constraint unavailableEmployee(ConstraintFactory constraintFactory) { return constraintFactory.forEach(Shift.class) .join(Availability.class, Joiners.equal((Shift shift) -> shift.getStart().toLocalDate(), Availability::getDate), Joiners.equal(Shift::getEmployee, Availability::getEmployee)) .filter((shift, availability) -> availability.getAvailabilityType() == AvailabilityType.UNAVAILABLE) .penalize(HardSoftScore.ONE_HARD, (shift, availability) -> getShiftDurationInMinutes(shift)) .asConstraint("Unavailable employee"); }
解决方案
核心修改点是替换原有的日期相等匹配逻辑,改为判断班次日期是否落在可用性的起止范围内,同时保留员工匹配条件,再根据可用性类型调整评分逻辑。
修改后的代码如下:
Constraint unavailableEmployee(ConstraintFactory constraintFactory) { return constraintFactory.forEach(Shift.class) // 匹配同一员工,且班次日期在可用性的起止范围内 .join(Availability.class, Joiners.equal(Shift::getEmployee, Availability::getEmployee), Joiners.filtering((shift, availability) -> { LocalDate shiftDate = shift.getStart().toLocalDate(); // 判断班次日期是否处于可用性的起止区间(包含两端日期) return !shiftDate.isBefore(availability.getStartDate()) && !shiftDate.isAfter(availability.getEndDate()); })) // 过滤出不可用类型的记录 .filter((shift, availability) -> availability.getAvailabilityType() == AvailabilityType.UNAVAILABLE) // 按班次时长施加硬惩罚,若需调整评分可修改此处分值 .penalize(HardSoftScore.ONE_HARD, (shift, availability) -> getShiftDurationInMinutes(shift)) .asConstraint("Unavailable employee"); }
关键修改说明
- 连接逻辑调整:移除原有的日期相等匹配,改用
Joiners.filtering实现日期范围判断,确保班次日期落在可用性的startDate到endDate区间内,同时保留员工匹配条件避免跨员工关联。 - 评分扩展性:如果需要针对不同可用性类型(如
PREFERRED)设置不同评分(软惩罚),可复制此约束结构,修改过滤条件和penalize的分值即可。 - 边界日期处理:使用
isBefore和isAfter确保边界日期(如班次日期等于可用性起止日期)也能被正确匹配,避免逻辑遗漏。
内容的提问来源于stack exchange,提问作者JasonCarter
相关产品推荐
相关产品推荐

