Commit fc922b6975bf37085b2b66ca35616a9294447dc0
1 parent
2cf45c5d
优化计算时间间隔天数
Showing
5 changed files
with
217 additions
and
129 deletions
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 | 13 | import com.zteits.urbanops.module.garden.dal.mysql.inspectionplan.InspectionPlanRoleMapper; |
| 14 | 14 | import com.zteits.urbanops.module.garden.enums.FinishStateEnum; |
| 15 | 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 | 18 | import com.zteits.urbanops.module.system.api.dept.DeptApi; |
| 18 | 19 | import com.zteits.urbanops.module.system.api.dept.dto.DeptRespDTO; |
| 19 | 20 | import com.zteits.urbanops.module.system.api.permission.RoleApi; |
| ... | ... | @@ -26,7 +27,6 @@ import org.springframework.transaction.annotation.Transactional; |
| 26 | 27 | import org.springframework.util.CollectionUtils; |
| 27 | 28 | import org.springframework.validation.annotation.Validated; |
| 28 | 29 | |
| 29 | -import java.time.LocalDate; | |
| 30 | 30 | import java.time.LocalDateTime; |
| 31 | 31 | import java.time.format.DateTimeFormatter; |
| 32 | 32 | import java.util.*; |
| ... | ... | @@ -78,20 +78,20 @@ public class InspectionPlanServiceImpl implements InspectionPlanService { |
| 78 | 78 | LocalDateTime now = LocalDateTime.now(); |
| 79 | 79 | String userId = SecurityFrameworkUtils.getLoginUserId() + ""; |
| 80 | 80 | String userName = SecurityFrameworkUtils.getLoginUserNickname(); |
| 81 | - int rateValue; | |
| 81 | + String rateValue; | |
| 82 | 82 | if (createReqVO.getRateValue().contains("/")) { |
| 83 | - rateValue = Integer.parseInt(createReqVO.getRateValue().split("/")[1]); | |
| 83 | + rateValue = createReqVO.getRateValue(); | |
| 84 | 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 | 90 | log.warn("获取两个时间之间间隔天数错误"); |
| 91 | 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 | 97 | //巡检计划list |
| ... | ... | @@ -139,13 +139,12 @@ public class InspectionPlanServiceImpl implements InspectionPlanService { |
| 139 | 139 | }); |
| 140 | 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 | 143 | InspectionPlanDetailDO entity = getInspectionPlanDetailDO(batchNo, createReqVO, roadReqVO, now); |
| 145 | 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 | 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 | 5 | import cn.hutool.core.util.RandomUtil; |
| 6 | 6 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| 7 | 7 | import com.zteits.urbanops.framework.common.pojo.CommonResult; |
| 8 | -import com.zteits.urbanops.framework.common.util.collection.CollectionUtils; | |
| 9 | 8 | import com.zteits.urbanops.framework.dict.core.DictFrameworkUtils; |
| 10 | 9 | import com.zteits.urbanops.framework.security.core.util.SecurityFrameworkUtils; |
| 10 | +import com.zteits.urbanops.module.garden.dal.dataobject.inspectionplan.InspectionPlanDetailDO; | |
| 11 | 11 | import com.zteits.urbanops.module.garden.dal.dataobject.maintainplan.MaintainPlanDetailDO; |
| 12 | 12 | import com.zteits.urbanops.module.garden.dal.dataobject.maintainplan.MaintainPlanRoleDO; |
| 13 | 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 | 15 | import com.zteits.urbanops.module.garden.dal.mysql.maintainplan.MaintainPlanRoleMapper; |
| 16 | 16 | import com.zteits.urbanops.module.garden.enums.FinishStateEnum; |
| 17 | 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 | 20 | import com.zteits.urbanops.module.system.api.dept.DeptApi; |
| 20 | 21 | import com.zteits.urbanops.module.system.api.dept.dto.DeptRespDTO; |
| 21 | 22 | import com.zteits.urbanops.module.system.api.permission.RoleApi; |
| ... | ... | @@ -24,13 +25,12 @@ import jodd.util.StringUtil; |
| 24 | 25 | import lombok.extern.slf4j.Slf4j; |
| 25 | 26 | import org.springframework.stereotype.Service; |
| 26 | 27 | import jakarta.annotation.Resource; |
| 28 | +import org.springframework.util.CollectionUtils; | |
| 27 | 29 | import org.springframework.validation.annotation.Validated; |
| 28 | 30 | |
| 29 | -import java.time.LocalDate; | |
| 30 | 31 | import java.time.LocalDateTime; |
| 31 | 32 | import java.time.format.DateTimeFormatter; |
| 32 | 33 | import java.util.*; |
| 33 | -import java.util.concurrent.atomic.AtomicInteger; | |
| 34 | 34 | import java.util.stream.Collectors; |
| 35 | 35 | |
| 36 | 36 | import com.zteits.urbanops.module.garden.controller.admin.maintainplan.vo.*; |
| ... | ... | @@ -81,20 +81,21 @@ public class MaintainPlanServiceImpl implements MaintainPlanService { |
| 81 | 81 | LocalDateTime now = LocalDateTime.now(); |
| 82 | 82 | String userId = SecurityFrameworkUtils.getLoginUserId()+""; |
| 83 | 83 | String userName = SecurityFrameworkUtils.getLoginUserNickname(); |
| 84 | - int rateValue; | |
| 84 | + String rateValue; | |
| 85 | 85 | if (createReqVO.getRateValue().contains("/")) { |
| 86 | - rateValue = Integer.parseInt(createReqVO.getRateValue().split("/")[1]); | |
| 86 | + rateValue = createReqVO.getRateValue(); | |
| 87 | 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 | 94 | log.warn("获取两个时间之间间隔天数错误"); |
| 94 | 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 | 101 | //巡检计划list |
| ... | ... | @@ -141,14 +142,12 @@ public class MaintainPlanServiceImpl implements MaintainPlanService { |
| 141 | 142 | roleList.add(maintainPlanRoleDO); |
| 142 | 143 | }); |
| 143 | 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 | 146 | MaintainPlanDetailDO entity = getMaintainPlanDetailDO(batchNo, createReqVO, roadReqVO, now); |
| 148 | 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 | 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 | 156 | \ No newline at end of file | ... | ... |