public class WorkTimeServiceImpl implements IWorkTimeService { @Autowired private HolidayService holidayService; private final LocalTime MORNING_START = LocalTime.of(8, 30); private final LocalTime MORNING_END = LocalTime.of(12, 0); private final LocalTime AFTERNOON_START = LocalTime.of(14, 0); private final LocalTime AFTERNOON_END = LocalTime.of(18, 0); private final BigDecimal WORK_TIME_ONE_DAY = new BigDecimal("7.5"); /** * 计算工作时间 * * @param param 工作时间参数 * @return 工作时长 */ @Override public BigDecimal getWorkTime(WorkTimeParam param) { BigDecimal hour = new BigDecimal("0"); if (!param.getKssj().isBefore(param.getJssj())) { throw new ValidateException("开始时间必须早于结束时间"); } LocalDateTime start = param.getKssj(); LocalDateTime end = param.getJssj(); // 计算介于开始日期与结束日期之间的工作日天数 hour = calculateWorkDaysBetweenDates(start, end, hour); // 处理开始日期和结束日期的独立计算 hour = calculateWorkTimeOnStartAndEndDates(start, end, hour); return hour; } /** * 计算开始日期和结束日期之间的工作日天数 * * @param start 开始日期时间 * @param end 结束日期时间 * @param hour 总工作时长 * @return 更新后的总工作时长 */ private BigDecimal calculateWorkDaysBetweenDates(LocalDateTime start, LocalDateTime end, BigDecimal hour) { LocalDate startDay = start.toLocalDate(); LocalDate endDay = end.toLocalDate(); LocalDate nextStartDay = startDay.plusDays(1); LocalDate endDayBefore = endDay.plusDays(-1); while (!nextStartDay.isAfter(endDayBefore)) { if (!holidaysService.isHoliday(DateUtils.dateToString(nextStartDay, DateUtils.YYYY_MM_DD))) { hour = hour.add(WORK_TIME_ONE_DAY); } nextStartDay = nextStartDay.plusDays(1); } return hour; } /** * 处理开始日期和结束日期的工作时间计算 * * @param start 开始日期时间 * @param end 结束日期时间 * @param hour 总工作时长 * @return 更新后的总工作时长 */ private BigDecimal calculateWorkTimeOnStartAndEndDates(LocalDateTime start, LocalDateTime end, BigDecimal hour) { LocalDate startDay = start.toLocalDate(); LocalDate endDay = end.toLocalDate(); LocalTime startTime = start.toLocalTime(); LocalTime endTime = end.toLocalTime(); if (startDay.equals(endDay)) { if (!holidaysService.isHoliday(DateUtils.dateToString(startDay, DateUtils.YYYY_MM_DD))) { hour = calculateWorkTimeOnSameDay(startTime, endTime, hour); } } else { if (!holidaysService.isHoliday(DateUtils.dateToString(startDay, DateUtils.YYYY_MM_DD))) { hour = calculateWorkTimeOnStartDay(startTime, hour); } if (!holidaysService.isHoliday(DateUtils.dateToString(endDay, DateUtils.YYYY_MM_DD))) { hour = calculateWorkTimeOnEndDay(endTime, hour); } } return hour; } /** * 计算同一天的工作时间 * * @param startTime 开始时间 * @param endTime 结束时间 * @param hour 总工作时长 * @return 更新后的总工作时长 */ private BigDecimal calculateWorkTimeOnSameDay(LocalTime startTime, LocalTime endTime, BigDecimal hour) { hour = calculateWorkTimeForPeriod(startTime, MORNING_START, MORNING_END, endTime, hour); hour = calculateWorkTimeForPeriod(startTime, AFTERNOON_START, AFTERNOON_END, endTime, hour); return hour; } /** * 计算开始日期的工作时间 * * @param startTime 开始时间 * @param hour 总工作时长 * @return 更新后的总工作时长 */ private BigDecimal calculateWorkTimeOnStartDay(LocalTime startTime, BigDecimal hour) { hour = calculateWorkTimeForPeriod(startTime, MORNING_START, MORNING_END, LocalTime.MAX, hour); hour = calculateWorkTimeForPeriod(startTime, AFTERNOON_START, AFTERNOON_END, LocalTime.MAX, hour); return hour; } /** * 计算结束日期的工作时间 * * @param endTime 结束时间 * @param hour 总工作时长 * @return 更新后的总工作时长 */ private BigDecimal calculateWorkTimeOnEndDay(LocalTime endTime, BigDecimal hour) { hour = calculateWorkTimeForPeriod(LocalTime.MIN, MORNING_START, MORNING_END, endTime, hour); hour = calculateWorkTimeForPeriod(LocalTime.MIN, AFTERNOON_START, AFTERNOON_END, endTime, hour); return hour; } /** * 计算特定时间段内的工作时间 * * @param startTime 开始时间 * @param periodStart 时间段开始 * @param periodEnd 时间段结束 * @param endTime 结束时间 * @param hour 总工作时长 * @return 更新后的总工作时长 */ private BigDecimal calculateWorkTimeForPeriod(LocalTime startTime, LocalTime periodStart, LocalTime periodEnd, LocalTime endTime, BigDecimal hour) { if (startTime.isBefore(periodStart)) { if (endTime.isAfter(periodStart) && endTime.isBefore(periodEnd)) { Duration workDuration = Duration.between(periodStart, endTime); BigDecimal divide = BigDecimal.valueOf(workDuration.toMinutes()).divide(new BigDecimal("60"), 1, BigDecimal.ROUND_HALF_UP); hour = hour.add(divide); } else if (endTime.isAfter(periodEnd)) { Duration workDuration = Duration.between(periodStart, periodEnd); BigDecimal divide = BigDecimal.valueOf(workDuration.toMinutes()).divide(new BigDecimal("60"), 1, BigDecimal.ROUND_HALF_UP); hour = hour.add(divide); } } else if (!startTime.isBefore(periodStart) &&!startTime.isAfter(periodEnd)) { if (endTime.isAfter(periodEnd)) { Duration workDuration = Duration.between(startTime, periodEnd); BigDecimal divide = BigDecimal.valueOf(workDuration.toMinutes()).divide(new BigDecimal("60"), 1, BigDecimal.ROUND_HALF_UP); hour = hour.add(divide); } else { Duration workDuration = Duration.between(startTime, endTime); BigDecimal divide = BigDecimal.valueOf(workDuration.toMinutes()).divide(new BigDecimal("60"), 1, BigDecimal.ROUND_HALF_UP); hour = hour.add(divide); } } return hour; } }
04-11
975