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 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 parseDayOfWeeks(String dayOfWeekStr) { Set 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; } }