java代码实现请假/加班时长计算

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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值