package jnpf.limsService.support;
|
|
import java.time.LocalDate;
|
import java.time.temporal.ChronoUnit;
|
import java.util.ArrayList;
|
import java.util.List;
|
import java.util.Locale;
|
|
/** 水系统 Renwu 周期日期计算。 */
|
public final class LimsSxtQuyangJihuaRenwuPlanner {
|
|
private LimsSxtQuyangJihuaRenwuPlanner() {
|
}
|
|
public static List<LocalDate> executionDates(LocalDate start, LocalDate end, String cycleType, int interval) {
|
validate(start, end, cycleType, interval);
|
String normalizedCycleType = cycleType.trim().toLowerCase(Locale.ROOT);
|
List<LocalDate> dates = new ArrayList<>();
|
for (LocalDate candidate = start; !candidate.isAfter(end); candidate = candidate.plusDays(1)) {
|
if (matchesCycle(start, candidate, normalizedCycleType, interval)) {
|
dates.add(candidate);
|
}
|
}
|
return dates;
|
}
|
|
private static boolean matchesCycle(LocalDate start, LocalDate candidate, String cycleType, int interval) {
|
long daysDiff = ChronoUnit.DAYS.between(start, candidate);
|
long step = executionStep(interval);
|
switch (cycleType) {
|
case "daily": return daysDiff % step == 0;
|
case "weekly": return candidate.getDayOfWeek() == start.getDayOfWeek() && (daysDiff / 7) % step == 0;
|
case "monthly": return isMatchingDayOfMonth(start, candidate) && monthsBetween(start, candidate) % step == 0;
|
case "quarterly":
|
long monthDiff = monthsBetween(start, candidate);
|
return isMatchingDayOfMonth(start, candidate) && monthDiff % 3 == 0 && (monthDiff / 3) % step == 0;
|
case "yearly": return isMatchingYearlyDate(start, candidate) && (candidate.getYear() - start.getYear()) % step == 0;
|
default: throw new IllegalArgumentException("未知的取样计划周期类型:" + cycleType);
|
}
|
}
|
|
private static long executionStep(int interval) {
|
return (long) interval + 1;
|
}
|
|
private static long monthsBetween(LocalDate start, LocalDate candidate) {
|
return ChronoUnit.MONTHS.between(start.withDayOfMonth(1), candidate.withDayOfMonth(1));
|
}
|
|
private static boolean isMatchingDayOfMonth(LocalDate start, LocalDate candidate) {
|
return start.getDayOfMonth() == start.lengthOfMonth()
|
? candidate.getDayOfMonth() == candidate.lengthOfMonth()
|
: start.getDayOfMonth() == candidate.getDayOfMonth();
|
}
|
|
private static boolean isMatchingYearlyDate(LocalDate start, LocalDate candidate) {
|
if (start.getMonthValue() == 2 && start.getDayOfMonth() == 29) {
|
return candidate.getMonthValue() == 2 && candidate.getDayOfMonth() == (candidate.isLeapYear() ? 29 : 28);
|
}
|
return start.getMonthValue() == candidate.getMonthValue() && start.getDayOfMonth() == candidate.getDayOfMonth();
|
}
|
|
private static void validate(LocalDate start, LocalDate end, String cycleType, int interval) {
|
if (start == null || end == null) throw new IllegalArgumentException("取样计划起止日期不能为空");
|
if (end.isBefore(start)) throw new IllegalArgumentException("取样计划结束日期不能早于开始日期");
|
if (cycleType == null || cycleType.trim().isEmpty()) throw new IllegalArgumentException("取样计划周期类型不能为空");
|
if (interval < 0) throw new IllegalArgumentException("取样计划周期间隔不能小于零");
|
}
|
}
|