Check week-ends in an interval

Viewed 43

I need to check in the last four weeks that my agent has at least one week-end with no work.

I don't know how to join the sunday and saturday (with no work) and count them.

Here is what i tried :

private Constraint oneWeekendForFourWeeks(ConstraintFactory constraintFactory) {
    return constraintFactory
            .from(Workingday.class)
            .filter(Workingday::isSunday) // we keep only sundays
            .join(constraintFactory.from(Workingday.class)
                            .filter(Workingday::isSunday),
                    equal(Workingday::getAgent),
                    Joiners.filtering((wd1, wd2)->{
                        LocalDate quatreSemaineAvant = wd1.getDayJava().minusWeeks(4);
                        Boolean wd2isAfterfourWeeksBeforeWd1 = wd2.getDayJava().compareTo(fourWeeksBefore) >= 0;
                        return wd2isAfterfourWeeksBeforeWd1 && wd2.getDayJava().isBefore(wd1.getDayJava());
                    })
            )
            .groupBy((sunday1, sunday2) -> sunday2)// i got my 4 sundays
            .join(constraintFactory.from(Workingday.class) // i try to get the 4 saturdays
                            .filter(Workingday::isSaturday),
                    equal(Workingday::getAgent),
                    Joiners.filtering((sunday, saturday)->{
                        LocalDate oneDayBefore = sunday.getDayJava().minusDays(1);;
                        return saturday.getDayJava().equals(oneDayBefore);
                    })
            )
            .filter((saturday, sunday) -> {
                return !saturday.hasRestdayBySolver() && !sunday.hasRestdayBySolver();
            })
            .groupBy((saturday, sunday) -> saturday, countBi())
            .filter((saturday, count)->count > 3) // if we got more than 4 weekends without rest day -> we penalize
            .penalizeConfigurable(ONE_WEEKEND_FOR_FOUR_WEEKS);
}

In debug, i can count 4 sundays, but for my second join it join me only one saturday. Maybe the problem is here ?

Thanx for your help !

Edit :

this is the solution i found, maybe not optimized :

private Constraint oneWeekendForFourWeeks(ConstraintFactory constraintFactory) {
    return constraintFactory
            .from(WorkingDay.class)
            .filter(WorkingDay::isMonday)
            .join(constraintFactory.from(WorkingDay.class)
                            .filter(WorkingDay::isSaturday), 
                    equal(WorkingDay::getAgent),
                    Joiners.filtering((monday, saturday) -> {
                        LocalDate fourWeeksBefore = monday.getDayJava().minusWeeks(4);
                        Boolean wd2isAfterfourWeeksBeforeWd1 = saturday.getDayJava().compareTo(fourWeeksBefore) >= 0;
                        return wd2isAfterfourWeeksBeforeWd1 && saturday.getDayJava().isBefore(monday.getDayJava());
                    })
            )
            .join(constraintFactory.from(WorkingDay.class)
                    .filter(WorkingDay::isSunday) 
            )
            .filter((monday, saturday, sunday) -> {
                LocalDate unDayAfter = saturday.getDayJava().plusDays(1);
                return sunday.getDayJava().equals(unDayAfter) && sunday.getAgent().equals(monday.getAgent());
            })
            .groupBy((monday, saturday, sunday) -> monday,
                    sum((monday, saturday, sunday) -> {if (saturday.hasRestdayBySolver() && sunday.hasRestdayBySolver()) {return 1;} else {return 0;}})
            ) 
            .filter((monday, sum) -> sum == 0)
            .penalizeConfigurable(ONE_WEEKEND_FOR_FOUR_WEEKS);
}
1 Answers

How about something like this?

.from(Workingday.class)
.filter(WorkingDay::isWeekendDay // returns true if Saturday or Sunday
     && WorkingDay::isLastFourWeeks)
.groupBy(Workingday::getAgent,
     countDistinct(workingDay
         -> workingDay.getLocalDate.toEpochDay() - (isSunday ? 1 : 0))
.filter((agent, weekendCount) -> weekendCount >= 4)
.penalize()

We bascially group by agent and count the distinct number of weekends. Each weekend is identified by the number of days since the epoch of the first day of that weekend (= the Saturday).

Elegant, no?

Related