package com.ruoyi.inspectiontask.service.impl;
|
|
import java.time.DayOfWeek;
|
import java.time.LocalDateTime;
|
import java.time.LocalTime;
|
import java.time.YearMonth;
|
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeParseException;
|
import java.util.HashSet;
|
import java.util.Set;
|
|
final class TimingTaskScheduleUtils {
|
|
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm");
|
|
private TimingTaskScheduleUtils() {
|
}
|
|
static LocalDateTime calculateFirstExecutionTime(String frequencyType, String frequencyDetail) {
|
return calculateNextExecutionTime(frequencyType, frequencyDetail, LocalDateTime.now().minusSeconds(1));
|
}
|
|
static LocalDateTime calculateNextExecutionTime(String frequencyType, String frequencyDetail, LocalDateTime currentTime) {
|
if (frequencyType == null || frequencyDetail == null) {
|
throw new IllegalArgumentException("任务参数不能为空");
|
}
|
switch (frequencyType.toUpperCase()) {
|
case "DAILY":
|
return calculateDailyNextTime(frequencyDetail, currentTime);
|
case "WEEKLY":
|
return calculateWeeklyNextTime(frequencyDetail, currentTime);
|
case "MONTHLY":
|
return calculateMonthlyNextTime(frequencyDetail, currentTime);
|
case "QUARTERLY":
|
return calculateQuarterlyNextTime(frequencyDetail, currentTime);
|
default:
|
throw new IllegalArgumentException("不支持的频率类型: " + frequencyType);
|
}
|
}
|
|
private static LocalDateTime calculateDailyNextTime(String timeStr, LocalDateTime current) {
|
LocalTime executionTime = parseTime(timeStr);
|
LocalDateTime nextTime = LocalDateTime.of(current.toLocalDate(), executionTime);
|
return current.isBefore(nextTime) ? nextTime : nextTime.plusDays(1);
|
}
|
|
private static LocalDateTime calculateWeeklyNextTime(String detail, LocalDateTime current) {
|
String[] parts = validateAndSplit(detail, ",", 2);
|
Set<DayOfWeek> targetDays = parseDayOfWeeks(parts[0]);
|
LocalTime time = parseTime(parts[1]);
|
|
LocalDateTime nextTime = current;
|
for (int i = 0; i < 366; i++) {
|
nextTime = nextTime.plusDays(1);
|
if (targetDays.contains(nextTime.getDayOfWeek())) {
|
return LocalDateTime.of(nextTime.toLocalDate(), time);
|
}
|
}
|
throw new IllegalArgumentException("无法找到下一次执行时间");
|
}
|
|
private static LocalDateTime calculateMonthlyNextTime(String detail, LocalDateTime current) {
|
String[] parts = validateAndSplit(detail, ",", 2);
|
int dayOfMonth = validateDayOfMonth(parts[0]);
|
LocalTime time = parseTime(parts[1]);
|
|
for (int i = 0; i < 24; i++) {
|
YearMonth targetYearMonth = YearMonth.from(current).plusMonths(i);
|
int adjustedDay = Math.min(dayOfMonth, targetYearMonth.lengthOfMonth());
|
LocalDateTime target = LocalDateTime.of(
|
targetYearMonth.getYear(),
|
targetYearMonth.getMonthValue(),
|
adjustedDay,
|
time.getHour(),
|
time.getMinute()
|
);
|
if (target.isAfter(current)) {
|
return target;
|
}
|
}
|
throw new IllegalArgumentException("无法找到下一次执行时间");
|
}
|
|
private static LocalDateTime calculateQuarterlyNextTime(String detail, LocalDateTime current) {
|
String[] parts = validateAndSplit(detail, ",", 3);
|
int startMonth = validateMonth(parts[0]);
|
int dayOfMonth = validateDayOfMonth(parts[1]);
|
LocalTime time = parseTime(parts[2]);
|
|
YearMonth anchor = YearMonth.of(current.getYear(), startMonth);
|
for (int i = 0; i < 12; i++) {
|
YearMonth targetYearMonth = anchor.plusMonths(3L * i);
|
int adjustedDay = Math.min(dayOfMonth, targetYearMonth.lengthOfMonth());
|
LocalDateTime target = LocalDateTime.of(
|
targetYearMonth.getYear(),
|
targetYearMonth.getMonthValue(),
|
adjustedDay,
|
time.getHour(),
|
time.getMinute()
|
);
|
if (target.isAfter(current)) {
|
return target;
|
}
|
}
|
throw new IllegalArgumentException("无法找到下一次执行时间");
|
}
|
|
private static LocalTime parseTime(String timeStr) {
|
try {
|
return LocalTime.parse(timeStr, TIME_FORMATTER);
|
} catch (DateTimeParseException e) {
|
throw new IllegalArgumentException("时间格式必须为HH:mm", e);
|
}
|
}
|
|
private static String[] validateAndSplit(String input, String delimiter, int expectedParts) {
|
String[] parts = input.split(delimiter);
|
if (parts.length != expectedParts) {
|
throw new IllegalArgumentException("参数格式错误");
|
}
|
return parts;
|
}
|
|
private static int validateDayOfMonth(String dayStr) {
|
int day = Integer.parseInt(dayStr.trim());
|
if (day < 1 || day > 31) {
|
throw new IllegalArgumentException("日期必须在1-31之间");
|
}
|
return day;
|
}
|
|
private static int validateMonth(String monthStr) {
|
int month = Integer.parseInt(monthStr.trim());
|
if (month < 1 || month > 12) {
|
throw new IllegalArgumentException("月份必须在1-12之间");
|
}
|
return month;
|
}
|
|
private static Set<DayOfWeek> parseDayOfWeeks(String dayOfWeekStr) {
|
Set<DayOfWeek> days = new HashSet<>();
|
for (String dayStr : dayOfWeekStr.split("\\|")) {
|
switch (dayStr.trim().toUpperCase()) {
|
case "MON":
|
days.add(DayOfWeek.MONDAY);
|
break;
|
case "TUE":
|
days.add(DayOfWeek.TUESDAY);
|
break;
|
case "WED":
|
days.add(DayOfWeek.WEDNESDAY);
|
break;
|
case "THU":
|
days.add(DayOfWeek.THURSDAY);
|
break;
|
case "FRI":
|
days.add(DayOfWeek.FRIDAY);
|
break;
|
case "SAT":
|
days.add(DayOfWeek.SATURDAY);
|
break;
|
case "SUN":
|
days.add(DayOfWeek.SUNDAY);
|
break;
|
default:
|
throw new IllegalArgumentException("无效的星期几: " + dayStr);
|
}
|
}
|
return days;
|
}
|
}
|