Commit fc922b6975bf37085b2b66ca35616a9294447dc0

Authored by 王富生
1 parent 2cf45c5d

优化计算时间间隔天数

urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/inspectionplan/InspectionPlanServiceImpl.java
@@ -13,7 +13,8 @@ import com.zteits.urbanops.module.garden.dal.mysql.inspectionplan.InspectionPlan @@ -13,7 +13,8 @@ import com.zteits.urbanops.module.garden.dal.mysql.inspectionplan.InspectionPlan
13 import com.zteits.urbanops.module.garden.dal.mysql.inspectionplan.InspectionPlanRoleMapper; 13 import com.zteits.urbanops.module.garden.dal.mysql.inspectionplan.InspectionPlanRoleMapper;
14 import com.zteits.urbanops.module.garden.enums.FinishStateEnum; 14 import com.zteits.urbanops.module.garden.enums.FinishStateEnum;
15 import com.zteits.urbanops.module.garden.enums.PlanConstants; 15 import com.zteits.urbanops.module.garden.enums.PlanConstants;
16 -import com.zteits.urbanops.module.garden.util.TimeIntervalCalculatorUtil; 16 +import com.zteits.urbanops.module.garden.util.timeinterval.PeriodResult;
  17 +import com.zteits.urbanops.module.garden.util.timeinterval.TimeIntervalFrequencyUtil;
17 import com.zteits.urbanops.module.system.api.dept.DeptApi; 18 import com.zteits.urbanops.module.system.api.dept.DeptApi;
18 import com.zteits.urbanops.module.system.api.dept.dto.DeptRespDTO; 19 import com.zteits.urbanops.module.system.api.dept.dto.DeptRespDTO;
19 import com.zteits.urbanops.module.system.api.permission.RoleApi; 20 import com.zteits.urbanops.module.system.api.permission.RoleApi;
@@ -26,7 +27,6 @@ import org.springframework.transaction.annotation.Transactional; @@ -26,7 +27,6 @@ import org.springframework.transaction.annotation.Transactional;
26 import org.springframework.util.CollectionUtils; 27 import org.springframework.util.CollectionUtils;
27 import org.springframework.validation.annotation.Validated; 28 import org.springframework.validation.annotation.Validated;
28 29
29 -import java.time.LocalDate;  
30 import java.time.LocalDateTime; 30 import java.time.LocalDateTime;
31 import java.time.format.DateTimeFormatter; 31 import java.time.format.DateTimeFormatter;
32 import java.util.*; 32 import java.util.*;
@@ -78,20 +78,20 @@ public class InspectionPlanServiceImpl implements InspectionPlanService { @@ -78,20 +78,20 @@ public class InspectionPlanServiceImpl implements InspectionPlanService {
78 LocalDateTime now = LocalDateTime.now(); 78 LocalDateTime now = LocalDateTime.now();
79 String userId = SecurityFrameworkUtils.getLoginUserId() + ""; 79 String userId = SecurityFrameworkUtils.getLoginUserId() + "";
80 String userName = SecurityFrameworkUtils.getLoginUserNickname(); 80 String userName = SecurityFrameworkUtils.getLoginUserNickname();
81 - int rateValue; 81 + String rateValue;
82 if (createReqVO.getRateValue().contains("/")) { 82 if (createReqVO.getRateValue().contains("/")) {
83 - rateValue = Integer.parseInt(createReqVO.getRateValue().split("/")[1]); 83 + rateValue = createReqVO.getRateValue();
84 } else { 84 } else {
85 - rateValue = Integer.parseInt(createReqVO.getRateValue()); 85 + rateValue = createReqVO.getRateValue()+"/1";
86 } 86 }
87 //计算开始和计算时间 在间隔周期下每天的次数 87 //计算开始和计算时间 在间隔周期下每天的次数
88 - List<String> betweenDayList = TimeIntervalCalculatorUtil.calculateIntervals(createReqVO.getBeginTime(), createReqVO.getEndTime(), createReqVO.getCycleId(), rateValue);  
89 - if (CollectionUtils.isEmpty(betweenDayList)) { 88 + List<PeriodResult> calculate = TimeIntervalFrequencyUtil.calculate(createReqVO.getBeginTime().toString(), createReqVO.getEndTime().toString(), rateValue, createReqVO.getCycleId());
  89 + if (CollectionUtils.isEmpty(calculate)) {
90 log.warn("获取两个时间之间间隔天数错误"); 90 log.warn("获取两个时间之间间隔天数错误");
91 return CommonResult.error(INSPECTION_CYCLE_ERROR); 91 return CommonResult.error(INSPECTION_CYCLE_ERROR);
92 } 92 }
93 //计算计划次数 93 //计算计划次数
94 - Integer planNum = betweenDayList.size(); 94 + Integer planNum = calculate.size();
95 95
96 96
97 //巡检计划list 97 //巡检计划list
@@ -139,13 +139,12 @@ public class InspectionPlanServiceImpl implements InspectionPlanService { @@ -139,13 +139,12 @@ public class InspectionPlanServiceImpl implements InspectionPlanService {
139 }); 139 });
140 /*3.插入巡查计划明细*/ 140 /*3.插入巡查计划明细*/
141 141
142 - for (int i = 0; i < betweenDayList.size(); i++) {  
143 - String[] dateStr = betweenDayList.get(i).split("/"); 142 + for (PeriodResult periodResult : calculate) {
144 InspectionPlanDetailDO entity = getInspectionPlanDetailDO(batchNo, createReqVO, roadReqVO, now); 143 InspectionPlanDetailDO entity = getInspectionPlanDetailDO(batchNo, createReqVO, roadReqVO, now);
145 ThreadUtil.sleep(2); 144 ThreadUtil.sleep(2);
146 - entity.setSortNum(i + 1);  
147 - entity.setBeginTime(LocalDateTime.parse(dateStr[0] + " 00:00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));  
148 - entity.setEndTime(LocalDateTime.parse(dateStr[1] + " 23:59:59", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); 145 + entity.setSortNum(periodResult.getCount());
  146 + entity.setBeginTime(LocalDateTime.parse(periodResult.getStart() + " 00:00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
  147 + entity.setEndTime(LocalDateTime.parse(periodResult.getEnd() + " 23:59:59", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
149 detailDOList.add(entity); 148 detailDOList.add(entity);
150 } 149 }
151 }); 150 });
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/maintainplan/MaintainPlanServiceImpl.java
@@ -5,9 +5,9 @@ import cn.hutool.core.thread.ThreadUtil; @@ -5,9 +5,9 @@ import cn.hutool.core.thread.ThreadUtil;
5 import cn.hutool.core.util.RandomUtil; 5 import cn.hutool.core.util.RandomUtil;
6 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 6 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
7 import com.zteits.urbanops.framework.common.pojo.CommonResult; 7 import com.zteits.urbanops.framework.common.pojo.CommonResult;
8 -import com.zteits.urbanops.framework.common.util.collection.CollectionUtils;  
9 import com.zteits.urbanops.framework.dict.core.DictFrameworkUtils; 8 import com.zteits.urbanops.framework.dict.core.DictFrameworkUtils;
10 import com.zteits.urbanops.framework.security.core.util.SecurityFrameworkUtils; 9 import com.zteits.urbanops.framework.security.core.util.SecurityFrameworkUtils;
  10 +import com.zteits.urbanops.module.garden.dal.dataobject.inspectionplan.InspectionPlanDetailDO;
11 import com.zteits.urbanops.module.garden.dal.dataobject.maintainplan.MaintainPlanDetailDO; 11 import com.zteits.urbanops.module.garden.dal.dataobject.maintainplan.MaintainPlanDetailDO;
12 import com.zteits.urbanops.module.garden.dal.dataobject.maintainplan.MaintainPlanRoleDO; 12 import com.zteits.urbanops.module.garden.dal.dataobject.maintainplan.MaintainPlanRoleDO;
13 import com.zteits.urbanops.module.garden.dal.mysql.maintainplan.MaintainPlanDetailMapper; 13 import com.zteits.urbanops.module.garden.dal.mysql.maintainplan.MaintainPlanDetailMapper;
@@ -15,7 +15,8 @@ import com.zteits.urbanops.module.garden.dal.mysql.maintainplan.MaintainPlanInte @@ -15,7 +15,8 @@ import com.zteits.urbanops.module.garden.dal.mysql.maintainplan.MaintainPlanInte
15 import com.zteits.urbanops.module.garden.dal.mysql.maintainplan.MaintainPlanRoleMapper; 15 import com.zteits.urbanops.module.garden.dal.mysql.maintainplan.MaintainPlanRoleMapper;
16 import com.zteits.urbanops.module.garden.enums.FinishStateEnum; 16 import com.zteits.urbanops.module.garden.enums.FinishStateEnum;
17 import com.zteits.urbanops.module.garden.enums.PlanConstants; 17 import com.zteits.urbanops.module.garden.enums.PlanConstants;
18 -import com.zteits.urbanops.module.garden.util.TimeIntervalCalculatorUtil; 18 +import com.zteits.urbanops.module.garden.util.timeinterval.PeriodResult;
  19 +import com.zteits.urbanops.module.garden.util.timeinterval.TimeIntervalFrequencyUtil;
19 import com.zteits.urbanops.module.system.api.dept.DeptApi; 20 import com.zteits.urbanops.module.system.api.dept.DeptApi;
20 import com.zteits.urbanops.module.system.api.dept.dto.DeptRespDTO; 21 import com.zteits.urbanops.module.system.api.dept.dto.DeptRespDTO;
21 import com.zteits.urbanops.module.system.api.permission.RoleApi; 22 import com.zteits.urbanops.module.system.api.permission.RoleApi;
@@ -24,13 +25,12 @@ import jodd.util.StringUtil; @@ -24,13 +25,12 @@ import jodd.util.StringUtil;
24 import lombok.extern.slf4j.Slf4j; 25 import lombok.extern.slf4j.Slf4j;
25 import org.springframework.stereotype.Service; 26 import org.springframework.stereotype.Service;
26 import jakarta.annotation.Resource; 27 import jakarta.annotation.Resource;
  28 +import org.springframework.util.CollectionUtils;
27 import org.springframework.validation.annotation.Validated; 29 import org.springframework.validation.annotation.Validated;
28 30
29 -import java.time.LocalDate;  
30 import java.time.LocalDateTime; 31 import java.time.LocalDateTime;
31 import java.time.format.DateTimeFormatter; 32 import java.time.format.DateTimeFormatter;
32 import java.util.*; 33 import java.util.*;
33 -import java.util.concurrent.atomic.AtomicInteger;  
34 import java.util.stream.Collectors; 34 import java.util.stream.Collectors;
35 35
36 import com.zteits.urbanops.module.garden.controller.admin.maintainplan.vo.*; 36 import com.zteits.urbanops.module.garden.controller.admin.maintainplan.vo.*;
@@ -81,20 +81,21 @@ public class MaintainPlanServiceImpl implements MaintainPlanService { @@ -81,20 +81,21 @@ public class MaintainPlanServiceImpl implements MaintainPlanService {
81 LocalDateTime now = LocalDateTime.now(); 81 LocalDateTime now = LocalDateTime.now();
82 String userId = SecurityFrameworkUtils.getLoginUserId()+""; 82 String userId = SecurityFrameworkUtils.getLoginUserId()+"";
83 String userName = SecurityFrameworkUtils.getLoginUserNickname(); 83 String userName = SecurityFrameworkUtils.getLoginUserNickname();
84 - int rateValue; 84 + String rateValue;
85 if (createReqVO.getRateValue().contains("/")) { 85 if (createReqVO.getRateValue().contains("/")) {
86 - rateValue = Integer.parseInt(createReqVO.getRateValue().split("/")[1]); 86 + rateValue = createReqVO.getRateValue();
87 } else { 87 } else {
88 - rateValue = Integer.parseInt(createReqVO.getRateValue()); 88 + rateValue = createReqVO.getRateValue()+"/1";
89 } 89 }
90 //计算开始和计算时间 在间隔周期下每天的次数 90 //计算开始和计算时间 在间隔周期下每天的次数
91 - List<String> betweenDayList = TimeIntervalCalculatorUtil.calculateIntervals(createReqVO.getBeginTime(), createReqVO.getEndTime(), createReqVO.getCycleId(), rateValue);  
92 - if (CollectionUtils.isAnyEmpty(betweenDayList)) { 91 + //计算开始和计算时间 在间隔周期下每天的次数
  92 + List<PeriodResult> calculate = TimeIntervalFrequencyUtil.calculate(createReqVO.getBeginTime().toString(), createReqVO.getEndTime().toString(), rateValue, createReqVO.getCycleId());
  93 + if (CollectionUtils.isEmpty(calculate)) {
93 log.warn("获取两个时间之间间隔天数错误"); 94 log.warn("获取两个时间之间间隔天数错误");
94 return CommonResult.error(INSPECTION_CYCLE_ERROR); 95 return CommonResult.error(INSPECTION_CYCLE_ERROR);
95 } 96 }
96 //计算计划次数 97 //计算计划次数
97 - Integer planNum = betweenDayList.size(); 98 + Integer planNum = calculate.size();
98 99
99 100
100 //巡检计划list 101 //巡检计划list
@@ -141,14 +142,12 @@ public class MaintainPlanServiceImpl implements MaintainPlanService { @@ -141,14 +142,12 @@ public class MaintainPlanServiceImpl implements MaintainPlanService {
141 roleList.add(maintainPlanRoleDO); 142 roleList.add(maintainPlanRoleDO);
142 }); 143 });
143 /*3.插入巡查计划明细*/ 144 /*3.插入巡查计划明细*/
144 -  
145 - for (int i = 0; i < betweenDayList.size(); i++) {  
146 - String[] dateStr = betweenDayList.get(i).split("/"); 145 + for (PeriodResult periodResult : calculate) {
147 MaintainPlanDetailDO entity = getMaintainPlanDetailDO(batchNo, createReqVO, roadReqVO, now); 146 MaintainPlanDetailDO entity = getMaintainPlanDetailDO(batchNo, createReqVO, roadReqVO, now);
148 ThreadUtil.sleep(2); 147 ThreadUtil.sleep(2);
149 - entity.setSortNum(i+1);  
150 - entity.setBeginTime(LocalDateTime.parse(dateStr[0] + " 00:00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));  
151 - entity.setEndTime(LocalDateTime.parse(dateStr[1] + " 23:59:59", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); 148 + entity.setSortNum(periodResult.getCount());
  149 + entity.setBeginTime(LocalDateTime.parse(periodResult.getStart() + " 00:00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
  150 + entity.setEndTime(LocalDateTime.parse(periodResult.getEnd() + " 23:59:59", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
152 detailDOList.add(entity); 151 detailDOList.add(entity);
153 } 152 }
154 }); 153 });
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/util/TimeIntervalCalculatorUtil.java deleted
1 -package com.zteits.urbanops.module.garden.util;  
2 -  
3 -  
4 -import java.time.LocalDate;  
5 -import java.util.ArrayList;  
6 -import java.util.List;  
7 -  
8 -import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception;  
9 -import static com.zteits.urbanops.module.garden.enums.ErrorCodeConstants.INSPECTION_CYCLE_ID_ERROR;  
10 -  
11 -public class TimeIntervalCalculatorUtil {  
12 - enum IntervalUnit {  
13 - DAY, WEEK, MONTH, YEAR  
14 - }  
15 -  
16 - public static void main(String[] args) {  
17 -  
18 - System.out.println("请输入开始日期(yyyy-MM-dd):");  
19 - LocalDate startDate = LocalDate.of(2025,10,1);  
20 -  
21 - System.out.println("请输入结束日期(yyyy-MM-dd):");  
22 - LocalDate endDate = LocalDate.of(2025,10,7);  
23 -  
24 - System.out.println("请选择间隔单位(1.天 2.周 3.月 4.年):");  
25 - IntervalUnit unit = IntervalUnit.DAY;  
26 -  
27 - System.out.println("请输入间隔数量(如2表示每2天/周/月/年):");  
28 - int intervalCount =2;  
29 -  
30 - List<String> intervals = calculateIntervals(startDate, endDate, 1, intervalCount);  
31 -  
32 - System.out.println("\n执行周期:");  
33 - intervals.forEach(System.out::println);  
34 - }  
35 -  
36 - /**  
37 - * 执行次数计算  
38 - * @param start  
39 - * @param end  
40 - * @param cycleId 1:日/次;2:周/次;3:月/次;4:年/次  
41 - * @param intervalCount  
42 - * @return  
43 - */  
44 - public static List<String> calculateIntervals(LocalDate start, LocalDate end, Integer cycleId, int intervalCount) {  
45 - List<String> intervals = new ArrayList<>();  
46 - LocalDate currentStart = start;  
47 - IntervalUnit unit = getIntervalUnit(cycleId);  
48 -  
49 - while (currentStart.isBefore(end) || currentStart.isEqual(end)) {  
50 - LocalDate currentEnd = calculateEndDate(currentStart, end, unit, intervalCount);  
51 - intervals.add(currentStart + "/" + currentEnd);  
52 - currentStart = currentEnd.plusDays(1);  
53 - }  
54 -  
55 - return intervals;  
56 - }  
57 -  
58 - private static LocalDate calculateEndDate(LocalDate currentStart, LocalDate endDate,  
59 - IntervalUnit unit, int intervalCount) {  
60 - switch (unit) {  
61 - case DAY:  
62 - LocalDate dayEnd = currentStart.plusDays(intervalCount - 1);  
63 - return dayEnd.isAfter(endDate) ? endDate : dayEnd;  
64 - case WEEK:  
65 - LocalDate weekEnd = currentStart.plusDays(7 * intervalCount - 1);  
66 - return weekEnd.isAfter(endDate) ? endDate : weekEnd;  
67 - case MONTH:  
68 - LocalDate monthEnd = currentStart.plusMonths(intervalCount)  
69 - .withDayOfMonth(1).minusDays(1);  
70 - return monthEnd.isAfter(endDate) ? endDate : monthEnd;  
71 - case YEAR:  
72 - LocalDate yearEnd = currentStart.plusYears(intervalCount)  
73 - .withDayOfYear(1).minusDays(1);  
74 - return yearEnd.isAfter(endDate) ? endDate : yearEnd;  
75 - default:  
76 - return endDate;  
77 - }  
78 - }  
79 -  
80 - /**  
81 - * 转换枚举  
82 - * @param cycleId 1:日/次;2:周/次;3:月/次;4:年/次  
83 - * @return  
84 - */  
85 - public static IntervalUnit getIntervalUnit(Integer cycleId) {  
86 - switch (cycleId) {  
87 - case 1:  
88 - return IntervalUnit.DAY;  
89 - case 2:  
90 - return IntervalUnit.WEEK;  
91 - case 3:  
92 - return IntervalUnit.MONTH;  
93 - case 4:  
94 - return IntervalUnit.YEAR;  
95 - default:  
96 - throw exception(INSPECTION_CYCLE_ID_ERROR);  
97 - }  
98 - }  
99 -  
100 -}  
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/util/timeinterval/PeriodResult.java 0 → 100644
  1 +package com.zteits.urbanops.module.garden.util.timeinterval;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import java.time.LocalDate;
  6 +import java.time.format.DateTimeFormatter;
  7 +
  8 +@Data
  9 +public class PeriodResult {
  10 + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
  11 +
  12 + /**
  13 + * 开始时间
  14 + */
  15 + private final String start;
  16 + /**
  17 + * 结束时间
  18 + */
  19 + private final String end;
  20 + /**
  21 + * 执行次数
  22 + */
  23 + private final int count;
  24 +
  25 + public PeriodResult(LocalDate start, LocalDate end, int count) {
  26 + this.start = start.format(FORMATTER);
  27 + this.end = end.format(FORMATTER);
  28 + this.count = count;
  29 + }
  30 +
  31 + @Override
  32 + public String toString() {
  33 + return start + " " + end + " " + count + "次";
  34 + }
  35 +}
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/util/timeinterval/TimeIntervalFrequencyUtil.java 0 → 100644
  1 +package com.zteits.urbanops.module.garden.util.timeinterval;
  2 +
  3 +import java.time.LocalDate;
  4 +import java.time.format.DateTimeFormatter;
  5 +import java.util.ArrayList;
  6 +import java.util.Collections;
  7 +import java.util.List;
  8 +
  9 +import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception;
  10 +import static com.zteits.urbanops.module.garden.enums.ErrorCodeConstants.INSPECTION_CYCLE_ID_ERROR;
  11 +
  12 +/**
  13 + * 时间区间拆分+频次计算工具类
  14 + * 支持:按日/周/月/年拆分,区间临界点重叠,动态计算每个区间的执行频次
  15 + */
  16 +public class TimeIntervalFrequencyUtil {
  17 +
  18 + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
  19 +
  20 + public enum IntervalUnit {
  21 + DAY, WEEK, MONTH, YEAR;
  22 + }
  23 +
  24 + /**
  25 + * 转换枚举
  26 + * @param cycleId 1:日/次;2:周/次;3:月/次;4:年/次
  27 + * @return
  28 + */
  29 + public static IntervalUnit getIntervalUnit(Integer cycleId) {
  30 + switch (cycleId) {
  31 + case 1:
  32 + return IntervalUnit.DAY;
  33 + case 2:
  34 + return IntervalUnit.WEEK;
  35 + case 3:
  36 + return IntervalUnit.MONTH;
  37 + case 4:
  38 + return IntervalUnit.YEAR;
  39 + default:
  40 + throw exception(INSPECTION_CYCLE_ID_ERROR);
  41 + }
  42 + }
  43 +
  44 + /**
  45 + * 计算时间段划分结果
  46 + *
  47 + * @param startStr 开始日期 (yyyy-MM-dd)
  48 + * @param endStr 结束日期 (yyyy-MM-dd)
  49 + * @param freq 频次值,格式 "x/y"
  50 + * @param cycleId cycleId 1:日/次;2:周/次;3:月/次;4:年/次
  51 + * @return 划分结果列表
  52 + */
  53 + public static List<PeriodResult> calculate(String startStr, String endStr, String freq, Integer cycleId) {
  54 + LocalDate start = LocalDate.parse(startStr, FORMATTER);
  55 + LocalDate end = LocalDate.parse(endStr, FORMATTER);
  56 +
  57 + if (start.isAfter(end)) {
  58 + return Collections.emptyList();
  59 + }
  60 +
  61 + String[] parts = freq.split("/", 2);
  62 + if (parts.length != 2) {
  63 + throw new IllegalArgumentException("频次值格式错误,应为 'x/y': " + freq);
  64 + }
  65 + int x = Integer.parseInt(parts[0]);
  66 + int y = Integer.parseInt(parts[1]);
  67 +
  68 + IntervalUnit unit = getIntervalUnit(cycleId);
  69 +
  70 + List<PeriodResult> results = new ArrayList<>();
  71 + LocalDate currentStart = start;
  72 +
  73 + while (!currentStart.isAfter(end)) {
  74 + // 计算当前周期的理论结束日期(包含 y 个单位)
  75 + LocalDate periodEnd = calculatePeriodEnd(currentStart, y, unit);
  76 +
  77 + // 实际段结束 = min(periodEnd, end)
  78 + LocalDate segEnd = periodEnd.isAfter(end) ? end : periodEnd;
  79 +
  80 + results.add(new PeriodResult(currentStart, segEnd, x));
  81 +
  82 + // 下一段从当前段结束的第二天开始
  83 + LocalDate nextStart = segEnd.plusDays(1);
  84 +
  85 + // 如果已经超过总结束时间,则终止
  86 + if (nextStart.isAfter(end)) {
  87 + break;
  88 + }
  89 +
  90 + currentStart = nextStart;
  91 + }
  92 +
  93 + return results;
  94 + }
  95 +
  96 + /**
  97 + * 计算从 start 开始,经过 y 个单位周期后的结束日期(包含)
  98 + */
  99 + private static LocalDate calculatePeriodEnd(LocalDate start, int y, IntervalUnit unit) {
  100 + switch (unit) {
  101 + case DAY:
  102 + return start.plusDays(y - 1); // 包含 y 天:start 到 start+y-1
  103 + case WEEK:
  104 + return start.plusDays((long) y * 7 - 1); // y周 = y*7天,减1得包含结束
  105 + case MONTH:
  106 + return addMonthsSafely(start, y).minusDays(1);
  107 + case YEAR:
  108 + return start.plusYears(y).minusDays(1);
  109 + default:
  110 + throw new UnsupportedOperationException("未支持的单位: " + unit);
  111 + }
  112 + }
  113 +
  114 +
  115 +
  116 + /**
  117 + * 安全地加上 y 个月(避免3月31日+1月变成异常)
  118 + * 这里使用 Java 8+ 的 plusMonths 自动调整规则
  119 + */
  120 + private static LocalDate addMonthsSafely(LocalDate date, int months) {
  121 + return date.plusMonths(months);
  122 + // Java 会自动处理:如 1月31日 +1月 → 2月28/29日(不会抛异常)
  123 + }
  124 +
  125 +
  126 +
  127 +
  128 + // ====================== 测试用例 ======================
  129 + //cycleId 1:日/次;2:周/次;3:月/次;4:年/次
  130 + public static void main(String[] args) {
  131 + System.out.println("=== 示例1:每3天一次,按日 ===");
  132 + List<PeriodResult> r1 = calculate("2025-01-01", "2025-01-07", "1/3", 1);
  133 + r1.forEach(System.out::println);
  134 +
  135 + System.out.println("\n=== 示例2:每3周一次(21天),按周 ===");
  136 + List<PeriodResult> r2 = calculate("2025-01-01", "2025-02-01", "1/3", 2);
  137 + r2.forEach(System.out::println);
  138 +
  139 + System.out.println("\n=== 示例3:每2个月一次,按月 ===");
  140 + List<PeriodResult> r3 = calculate("2025-01-01", "2025-12-31", "1/2", 3);
  141 + r3.forEach(System.out::println);
  142 +
  143 + System.out.println("\n=== 示例4:每3年一次,按年 ===");
  144 + List<PeriodResult> r4 = calculate("2025-01-01", "2035-06-01", "1/3", 3);
  145 + r4.forEach(System.out::println);
  146 +
  147 + System.out.println("\n=== 示例5:每2天2次,按日 ===");
  148 + List<PeriodResult> r5 = calculate("2025-01-01", "2025-01-05", "2/2", 1);
  149 + r5.forEach(System.out::println);
  150 +
  151 + System.out.println("\n=== 示例5:每2年1次,按年 ===");
  152 + List<PeriodResult> r6 = calculate("2025-01-01", "2028-01-05", "1/2", 4);
  153 + r6.forEach(System.out::println);
  154 + }
  155 +}
0 \ No newline at end of file 156 \ No newline at end of file