From 34981c30a78e8bbd7791131059a9210f9928b62c Mon Sep 17 00:00:00 2001
From: 刘光辉 <347230014@qq.com>
Date: 星期四, 17 九月 2026 09:24:09 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master' into master
---
jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/support/LimsSxtQuyangJihuaRenwuPlanner.java | 69 ++++++++++++++++++++++++++++++++++
1 files changed, 69 insertions(+), 0 deletions(-)
diff --git a/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/support/LimsSxtQuyangJihuaRenwuPlanner.java b/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/support/LimsSxtQuyangJihuaRenwuPlanner.java
new file mode 100644
index 0000000..a3da5d3
--- /dev/null
+++ b/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/support/LimsSxtQuyangJihuaRenwuPlanner.java
@@ -0,0 +1,69 @@
+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("鍙栨牱璁″垝鍛ㄦ湡闂撮殧涓嶈兘灏忎簬闆�");
+ }
+}
--
Gitblit v1.8.0