From fc922b6975bf37085b2b66ca35616a9294447dc0 Mon Sep 17 00:00:00 2001 From: wangfs <15029758498@163.com> Date: Fri, 5 Dec 2025 02:02:31 +0800 Subject: [PATCH] 优化计算时间间隔天数 --- urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/inspectionplan/InspectionPlanServiceImpl.java | 25 ++++++++++++------------- urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/maintainplan/MaintainPlanServiceImpl.java | 31 +++++++++++++++---------------- urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/util/TimeIntervalCalculatorUtil.java | 100 ---------------------------------------------------------------------------------------------------- urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/util/timeinterval/PeriodResult.java | 35 +++++++++++++++++++++++++++++++++++ urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/util/timeinterval/TimeIntervalFrequencyUtil.java | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 217 insertions(+), 129 deletions(-) delete mode 100644 urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/util/TimeIntervalCalculatorUtil.java create mode 100644 urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/util/timeinterval/PeriodResult.java create mode 100644 urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/util/timeinterval/TimeIntervalFrequencyUtil.java diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/inspectionplan/InspectionPlanServiceImpl.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/inspectionplan/InspectionPlanServiceImpl.java index 5b5c674..bb91920 100644 --- a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/inspectionplan/InspectionPlanServiceImpl.java +++ b/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 import com.zteits.urbanops.module.garden.dal.mysql.inspectionplan.InspectionPlanRoleMapper; import com.zteits.urbanops.module.garden.enums.FinishStateEnum; import com.zteits.urbanops.module.garden.enums.PlanConstants; -import com.zteits.urbanops.module.garden.util.TimeIntervalCalculatorUtil; +import com.zteits.urbanops.module.garden.util.timeinterval.PeriodResult; +import com.zteits.urbanops.module.garden.util.timeinterval.TimeIntervalFrequencyUtil; import com.zteits.urbanops.module.system.api.dept.DeptApi; import com.zteits.urbanops.module.system.api.dept.dto.DeptRespDTO; import com.zteits.urbanops.module.system.api.permission.RoleApi; @@ -26,7 +27,6 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import org.springframework.validation.annotation.Validated; -import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; @@ -78,20 +78,20 @@ public class InspectionPlanServiceImpl implements InspectionPlanService { LocalDateTime now = LocalDateTime.now(); String userId = SecurityFrameworkUtils.getLoginUserId() + ""; String userName = SecurityFrameworkUtils.getLoginUserNickname(); - int rateValue; + String rateValue; if (createReqVO.getRateValue().contains("/")) { - rateValue = Integer.parseInt(createReqVO.getRateValue().split("/")[1]); + rateValue = createReqVO.getRateValue(); } else { - rateValue = Integer.parseInt(createReqVO.getRateValue()); + rateValue = createReqVO.getRateValue()+"/1"; } //计算开始和计算时间 在间隔周期下每天的次数 - List betweenDayList = TimeIntervalCalculatorUtil.calculateIntervals(createReqVO.getBeginTime(), createReqVO.getEndTime(), createReqVO.getCycleId(), rateValue); - if (CollectionUtils.isEmpty(betweenDayList)) { + List calculate = TimeIntervalFrequencyUtil.calculate(createReqVO.getBeginTime().toString(), createReqVO.getEndTime().toString(), rateValue, createReqVO.getCycleId()); + if (CollectionUtils.isEmpty(calculate)) { log.warn("获取两个时间之间间隔天数错误"); return CommonResult.error(INSPECTION_CYCLE_ERROR); } //计算计划次数 - Integer planNum = betweenDayList.size(); + Integer planNum = calculate.size(); //巡检计划list @@ -139,13 +139,12 @@ public class InspectionPlanServiceImpl implements InspectionPlanService { }); /*3.插入巡查计划明细*/ - for (int i = 0; i < betweenDayList.size(); i++) { - String[] dateStr = betweenDayList.get(i).split("/"); + for (PeriodResult periodResult : calculate) { InspectionPlanDetailDO entity = getInspectionPlanDetailDO(batchNo, createReqVO, roadReqVO, now); ThreadUtil.sleep(2); - entity.setSortNum(i + 1); - entity.setBeginTime(LocalDateTime.parse(dateStr[0] + " 00:00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); - entity.setEndTime(LocalDateTime.parse(dateStr[1] + " 23:59:59", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); + entity.setSortNum(periodResult.getCount()); + entity.setBeginTime(LocalDateTime.parse(periodResult.getStart() + " 00:00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); + entity.setEndTime(LocalDateTime.parse(periodResult.getEnd() + " 23:59:59", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); detailDOList.add(entity); } }); diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/maintainplan/MaintainPlanServiceImpl.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/maintainplan/MaintainPlanServiceImpl.java index 613a390..dabd38c 100644 --- a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/maintainplan/MaintainPlanServiceImpl.java +++ b/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; import cn.hutool.core.util.RandomUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.zteits.urbanops.framework.common.pojo.CommonResult; -import com.zteits.urbanops.framework.common.util.collection.CollectionUtils; import com.zteits.urbanops.framework.dict.core.DictFrameworkUtils; import com.zteits.urbanops.framework.security.core.util.SecurityFrameworkUtils; +import com.zteits.urbanops.module.garden.dal.dataobject.inspectionplan.InspectionPlanDetailDO; import com.zteits.urbanops.module.garden.dal.dataobject.maintainplan.MaintainPlanDetailDO; import com.zteits.urbanops.module.garden.dal.dataobject.maintainplan.MaintainPlanRoleDO; import com.zteits.urbanops.module.garden.dal.mysql.maintainplan.MaintainPlanDetailMapper; @@ -15,7 +15,8 @@ import com.zteits.urbanops.module.garden.dal.mysql.maintainplan.MaintainPlanInte import com.zteits.urbanops.module.garden.dal.mysql.maintainplan.MaintainPlanRoleMapper; import com.zteits.urbanops.module.garden.enums.FinishStateEnum; import com.zteits.urbanops.module.garden.enums.PlanConstants; -import com.zteits.urbanops.module.garden.util.TimeIntervalCalculatorUtil; +import com.zteits.urbanops.module.garden.util.timeinterval.PeriodResult; +import com.zteits.urbanops.module.garden.util.timeinterval.TimeIntervalFrequencyUtil; import com.zteits.urbanops.module.system.api.dept.DeptApi; import com.zteits.urbanops.module.system.api.dept.dto.DeptRespDTO; import com.zteits.urbanops.module.system.api.permission.RoleApi; @@ -24,13 +25,12 @@ import jodd.util.StringUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import jakarta.annotation.Resource; +import org.springframework.util.CollectionUtils; import org.springframework.validation.annotation.Validated; -import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import com.zteits.urbanops.module.garden.controller.admin.maintainplan.vo.*; @@ -81,20 +81,21 @@ public class MaintainPlanServiceImpl implements MaintainPlanService { LocalDateTime now = LocalDateTime.now(); String userId = SecurityFrameworkUtils.getLoginUserId()+""; String userName = SecurityFrameworkUtils.getLoginUserNickname(); - int rateValue; + String rateValue; if (createReqVO.getRateValue().contains("/")) { - rateValue = Integer.parseInt(createReqVO.getRateValue().split("/")[1]); + rateValue = createReqVO.getRateValue(); } else { - rateValue = Integer.parseInt(createReqVO.getRateValue()); + rateValue = createReqVO.getRateValue()+"/1"; } //计算开始和计算时间 在间隔周期下每天的次数 - List betweenDayList = TimeIntervalCalculatorUtil.calculateIntervals(createReqVO.getBeginTime(), createReqVO.getEndTime(), createReqVO.getCycleId(), rateValue); - if (CollectionUtils.isAnyEmpty(betweenDayList)) { + //计算开始和计算时间 在间隔周期下每天的次数 + List calculate = TimeIntervalFrequencyUtil.calculate(createReqVO.getBeginTime().toString(), createReqVO.getEndTime().toString(), rateValue, createReqVO.getCycleId()); + if (CollectionUtils.isEmpty(calculate)) { log.warn("获取两个时间之间间隔天数错误"); return CommonResult.error(INSPECTION_CYCLE_ERROR); } //计算计划次数 - Integer planNum = betweenDayList.size(); + Integer planNum = calculate.size(); //巡检计划list @@ -141,14 +142,12 @@ public class MaintainPlanServiceImpl implements MaintainPlanService { roleList.add(maintainPlanRoleDO); }); /*3.插入巡查计划明细*/ - - for (int i = 0; i < betweenDayList.size(); i++) { - String[] dateStr = betweenDayList.get(i).split("/"); + for (PeriodResult periodResult : calculate) { MaintainPlanDetailDO entity = getMaintainPlanDetailDO(batchNo, createReqVO, roadReqVO, now); ThreadUtil.sleep(2); - entity.setSortNum(i+1); - entity.setBeginTime(LocalDateTime.parse(dateStr[0] + " 00:00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); - entity.setEndTime(LocalDateTime.parse(dateStr[1] + " 23:59:59", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); + entity.setSortNum(periodResult.getCount()); + entity.setBeginTime(LocalDateTime.parse(periodResult.getStart() + " 00:00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); + entity.setEndTime(LocalDateTime.parse(periodResult.getEnd() + " 23:59:59", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); detailDOList.add(entity); } }); diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/util/TimeIntervalCalculatorUtil.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/util/TimeIntervalCalculatorUtil.java deleted file mode 100644 index 6f0fa26..0000000 --- a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/util/TimeIntervalCalculatorUtil.java +++ /dev/null @@ -1,100 +0,0 @@ -package com.zteits.urbanops.module.garden.util; - - -import java.time.LocalDate; -import java.util.ArrayList; -import java.util.List; - -import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception; -import static com.zteits.urbanops.module.garden.enums.ErrorCodeConstants.INSPECTION_CYCLE_ID_ERROR; - -public class TimeIntervalCalculatorUtil { - enum IntervalUnit { - DAY, WEEK, MONTH, YEAR - } - - public static void main(String[] args) { - - System.out.println("请输入开始日期(yyyy-MM-dd):"); - LocalDate startDate = LocalDate.of(2025,10,1); - - System.out.println("请输入结束日期(yyyy-MM-dd):"); - LocalDate endDate = LocalDate.of(2025,10,7); - - System.out.println("请选择间隔单位(1.天 2.周 3.月 4.年):"); - IntervalUnit unit = IntervalUnit.DAY; - - System.out.println("请输入间隔数量(如2表示每2天/周/月/年):"); - int intervalCount =2; - - List intervals = calculateIntervals(startDate, endDate, 1, intervalCount); - - System.out.println("\n执行周期:"); - intervals.forEach(System.out::println); - } - - /** - * 执行次数计算 - * @param start - * @param end - * @param cycleId 1:日/次;2:周/次;3:月/次;4:年/次 - * @param intervalCount - * @return - */ - public static List calculateIntervals(LocalDate start, LocalDate end, Integer cycleId, int intervalCount) { - List intervals = new ArrayList<>(); - LocalDate currentStart = start; - IntervalUnit unit = getIntervalUnit(cycleId); - - while (currentStart.isBefore(end) || currentStart.isEqual(end)) { - LocalDate currentEnd = calculateEndDate(currentStart, end, unit, intervalCount); - intervals.add(currentStart + "/" + currentEnd); - currentStart = currentEnd.plusDays(1); - } - - return intervals; - } - - private static LocalDate calculateEndDate(LocalDate currentStart, LocalDate endDate, - IntervalUnit unit, int intervalCount) { - switch (unit) { - case DAY: - LocalDate dayEnd = currentStart.plusDays(intervalCount - 1); - return dayEnd.isAfter(endDate) ? endDate : dayEnd; - case WEEK: - LocalDate weekEnd = currentStart.plusDays(7 * intervalCount - 1); - return weekEnd.isAfter(endDate) ? endDate : weekEnd; - case MONTH: - LocalDate monthEnd = currentStart.plusMonths(intervalCount) - .withDayOfMonth(1).minusDays(1); - return monthEnd.isAfter(endDate) ? endDate : monthEnd; - case YEAR: - LocalDate yearEnd = currentStart.plusYears(intervalCount) - .withDayOfYear(1).minusDays(1); - return yearEnd.isAfter(endDate) ? endDate : yearEnd; - default: - return endDate; - } - } - - /** - * 转换枚举 - * @param cycleId 1:日/次;2:周/次;3:月/次;4:年/次 - * @return - */ - public static IntervalUnit getIntervalUnit(Integer cycleId) { - switch (cycleId) { - case 1: - return IntervalUnit.DAY; - case 2: - return IntervalUnit.WEEK; - case 3: - return IntervalUnit.MONTH; - case 4: - return IntervalUnit.YEAR; - default: - throw exception(INSPECTION_CYCLE_ID_ERROR); - } - } - -} diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/util/timeinterval/PeriodResult.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/util/timeinterval/PeriodResult.java new file mode 100644 index 0000000..7d03205 --- /dev/null +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/util/timeinterval/PeriodResult.java @@ -0,0 +1,35 @@ +package com.zteits.urbanops.module.garden.util.timeinterval; + +import lombok.Data; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +@Data +public class PeriodResult { + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + /** + * 开始时间 + */ + private final String start; + /** + * 结束时间 + */ + private final String end; + /** + * 执行次数 + */ + private final int count; + + public PeriodResult(LocalDate start, LocalDate end, int count) { + this.start = start.format(FORMATTER); + this.end = end.format(FORMATTER); + this.count = count; + } + + @Override + public String toString() { + return start + " " + end + " " + count + "次"; + } +} diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/util/timeinterval/TimeIntervalFrequencyUtil.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/util/timeinterval/TimeIntervalFrequencyUtil.java new file mode 100644 index 0000000..f4dbcf1 --- /dev/null +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/util/timeinterval/TimeIntervalFrequencyUtil.java @@ -0,0 +1,155 @@ +package com.zteits.urbanops.module.garden.util.timeinterval; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception; +import static com.zteits.urbanops.module.garden.enums.ErrorCodeConstants.INSPECTION_CYCLE_ID_ERROR; + +/** + * 时间区间拆分+频次计算工具类 + * 支持:按日/周/月/年拆分,区间临界点重叠,动态计算每个区间的执行频次 + */ +public class TimeIntervalFrequencyUtil { + + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + public enum IntervalUnit { + DAY, WEEK, MONTH, YEAR; + } + + /** + * 转换枚举 + * @param cycleId 1:日/次;2:周/次;3:月/次;4:年/次 + * @return + */ + public static IntervalUnit getIntervalUnit(Integer cycleId) { + switch (cycleId) { + case 1: + return IntervalUnit.DAY; + case 2: + return IntervalUnit.WEEK; + case 3: + return IntervalUnit.MONTH; + case 4: + return IntervalUnit.YEAR; + default: + throw exception(INSPECTION_CYCLE_ID_ERROR); + } + } + + /** + * 计算时间段划分结果 + * + * @param startStr 开始日期 (yyyy-MM-dd) + * @param endStr 结束日期 (yyyy-MM-dd) + * @param freq 频次值,格式 "x/y" + * @param cycleId cycleId 1:日/次;2:周/次;3:月/次;4:年/次 + * @return 划分结果列表 + */ + public static List calculate(String startStr, String endStr, String freq, Integer cycleId) { + LocalDate start = LocalDate.parse(startStr, FORMATTER); + LocalDate end = LocalDate.parse(endStr, FORMATTER); + + if (start.isAfter(end)) { + return Collections.emptyList(); + } + + String[] parts = freq.split("/", 2); + if (parts.length != 2) { + throw new IllegalArgumentException("频次值格式错误,应为 'x/y': " + freq); + } + int x = Integer.parseInt(parts[0]); + int y = Integer.parseInt(parts[1]); + + IntervalUnit unit = getIntervalUnit(cycleId); + + List results = new ArrayList<>(); + LocalDate currentStart = start; + + while (!currentStart.isAfter(end)) { + // 计算当前周期的理论结束日期(包含 y 个单位) + LocalDate periodEnd = calculatePeriodEnd(currentStart, y, unit); + + // 实际段结束 = min(periodEnd, end) + LocalDate segEnd = periodEnd.isAfter(end) ? end : periodEnd; + + results.add(new PeriodResult(currentStart, segEnd, x)); + + // 下一段从当前段结束的第二天开始 + LocalDate nextStart = segEnd.plusDays(1); + + // 如果已经超过总结束时间,则终止 + if (nextStart.isAfter(end)) { + break; + } + + currentStart = nextStart; + } + + return results; + } + + /** + * 计算从 start 开始,经过 y 个单位周期后的结束日期(包含) + */ + private static LocalDate calculatePeriodEnd(LocalDate start, int y, IntervalUnit unit) { + switch (unit) { + case DAY: + return start.plusDays(y - 1); // 包含 y 天:start 到 start+y-1 + case WEEK: + return start.plusDays((long) y * 7 - 1); // y周 = y*7天,减1得包含结束 + case MONTH: + return addMonthsSafely(start, y).minusDays(1); + case YEAR: + return start.plusYears(y).minusDays(1); + default: + throw new UnsupportedOperationException("未支持的单位: " + unit); + } + } + + + + /** + * 安全地加上 y 个月(避免3月31日+1月变成异常) + * 这里使用 Java 8+ 的 plusMonths 自动调整规则 + */ + private static LocalDate addMonthsSafely(LocalDate date, int months) { + return date.plusMonths(months); + // Java 会自动处理:如 1月31日 +1月 → 2月28/29日(不会抛异常) + } + + + + + // ====================== 测试用例 ====================== + //cycleId 1:日/次;2:周/次;3:月/次;4:年/次 + public static void main(String[] args) { + System.out.println("=== 示例1:每3天一次,按日 ==="); + List r1 = calculate("2025-01-01", "2025-01-07", "1/3", 1); + r1.forEach(System.out::println); + + System.out.println("\n=== 示例2:每3周一次(21天),按周 ==="); + List r2 = calculate("2025-01-01", "2025-02-01", "1/3", 2); + r2.forEach(System.out::println); + + System.out.println("\n=== 示例3:每2个月一次,按月 ==="); + List r3 = calculate("2025-01-01", "2025-12-31", "1/2", 3); + r3.forEach(System.out::println); + + System.out.println("\n=== 示例4:每3年一次,按年 ==="); + List r4 = calculate("2025-01-01", "2035-06-01", "1/3", 3); + r4.forEach(System.out::println); + + System.out.println("\n=== 示例5:每2天2次,按日 ==="); + List r5 = calculate("2025-01-01", "2025-01-05", "2/2", 1); + r5.forEach(System.out::println); + + System.out.println("\n=== 示例5:每2年1次,按年 ==="); + List r6 = calculate("2025-01-01", "2028-01-05", "1/2", 4); + r6.forEach(System.out::println); + } +} \ No newline at end of file -- libgit2 0.21.4