javaoptaplannertimefold

How to accumulate shift duration with day setting


I have a shift class, that returns the information for the shift.

public class Shift {
    @PlanningId
    private String id;

    private LocalDateTime start;
    private LocalDateTime end;
    public Long getShiftDuration() {
        long minutes = ChronoUnit.MINUTES.between(start, end);
        
        return minutes;
    }
    
    public String getBusinessDate() {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String dateStr = getStart().toLocalDate().format(formatter);
        return dateStr;
    }
}

Then I have a class DaySettingFlat, that contains the list of dates that we need to calculate sum of shift durations. The date mentioned in DaySettingFlat contains a variable businessDate which will contain a date. With this date value we have to sum the durations of the Shift collection that matched with the businessDate.

public class DaySettingFlat {
    String businessDate;
    Integer sumOfShiftDuration;
}

The both class is registered as @ProblemFactCollectionProperty. Now for each DaySettingFlat entry, we have to sum the duration of the shifts for a date stored in businessDate. Both the Shift and DaySettingFlat are used as a collection.

I tried like follows but it's not working, it's giving compilation error:

    Constraint daySettingStandardNumberOfHours(ConstraintFactory constraintFactory) {
        return constraintFactory.forEach(DaySettingFlat.class)
                .join(Shift.class, equal(DaySettingFlat::getBusinessDate, Shift::getStartDate))
//Getting error on group by 
                .groupBy(Shift::getStartDate,
                         ConstraintCollectors.toList(),
                         ConstraintCollectors.sumLong(Shift::getShiftDuration))
                .penalize(HardMediumSoftScore.ONE_HARD, (date, list, totalDuration)->{
                    return totalDuration;
                }).asConstraint("daySettingStandardNumberOfHours");
    }

Solution

  • The reason it is not working is because you have a BiConstraintStream, so you need to provide a function that takes both DaySettingFlat and Shift:

        Constraint daySettingStandardNumberOfHours(ConstraintFactory constraintFactory) {
            return constraintFactory.forEach(DaySettingFlat.class)
                    .join(Shift.class, equal(DaySettingFlat::getBusinessDate, Shift::getStartDate))
                    .groupBy((day, shift) -> shift.getStartDate(),
                             ConstraintCollectors.toList((day, shift) -> day),
                             ConstraintCollectors.sumLong((day, shift) -> shift.getShiftDuration()))
                    .penalize(HardMediumSoftScore.ONE_HARD, (date, list, totalDuration)->{
                        return totalDuration;
                    }).asConstraint("daySettingStandardNumberOfHours");
        }
    

    Is the list doing anything? It is unused in the Constraint you provided. If not, I recommend removing it.