计算工作日的工时数

计算上班工作日的工时数

最近公司要求去计算工时数:
公司上班情况:
1.早上8:30 到 下午的 17:30 , 中午午休时间 12:00 - 13:00 午休一个小时
2.只计算周一到周五,上班的时间,周六日工时数去除
3.午休的一个小时不包含在工作数中
4.设计到跨天计算,比如计算2024-08-27 9:00 到 2024-8-29 17:00

针对以上这种情况,提供如下方法来解决

 // 定义工作开始和结束时间,午休开始和结束时间
    private static final LocalTime WORK_START = LocalTime.of(8, 30);
    private static final LocalTime WORK_END = LocalTime.of(17, 30);
    private static final LocalTime BREAK_START = LocalTime.of(12, 0);
    private static final LocalTime BREAK_END = LocalTime.of(13, 0);

    @Override
    public double calculateWorkingHoursAcrossDays(ConfirmHours confirmHours) {
         // 开始时间和结束时间
         LocalDateTime startTime = confirmHours.getBeginTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
         LocalDateTime endTime = confirmHours.getEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        boolean addLunchWorkHour = confirmHours.isAddLunchWorkHour();
        // 跨天情况
        if (startTime.toLocalDate().isBefore(endTime.toLocalDate())) {
            return roundToTwoDecimalPlaces(calculateCrossDayWorkMinutes(startTime, endTime,addLunchWorkHour) / 60.0); // 将分钟转换为小时并显示
        } else {
            // 同一天的情况
            return roundToTwoDecimalPlaces(calculateSingleDayWorkMinutes(startTime, endTime, addLunchWorkHour) / 60.0);
        }
    }


    // 将数字保留两位小数
    private double roundToTwoDecimalPlaces(double number) {
        DecimalFormat df = new DecimalFormat("#.##");
        return Double.parseDouble(df.format(number));
    }

    private static long calculateCrossDayWorkMinutes(LocalDateTime startTime, LocalDateTime endTime,boolean addLunchWorkHour) {
        LocalDateTime endOfFirstDay = LocalDateTime.of(startTime.toLocalDate(), WORK_END);
        LocalDateTime startOfSecondDay = LocalDateTime.of(endTime.toLocalDate(), WORK_START);

        long firstDayWorkMinutes = calculateSingleDayWorkMinutes(startTime, endOfFirstDay,addLunchWorkHour);
        long secondDayWorkMinutes = calculateSingleDayWorkMinutes(startOfSecondDay, endTime,addLunchWorkHour);

        // 计算中间完整工作天数,排除周末
        long fullDays = ChronoUnit.DAYS.between(startTime.toLocalDate().plusDays(1), endTime.toLocalDate());

        long workDayCount = 0;
        for (int i = 0; i < fullDays; i++) {
            LocalDate tempDate = startTime.toLocalDate().plusDays(i + 1);
            if (isWorkDay(tempDate.atStartOfDay())) {
                workDayCount++;
            }
        }

        // 计算中间完整工作日的工时(按分钟计算)
        long fullDayWorkMinutes = 480;
        if (addLunchWorkHour) {
            fullDayWorkMinutes += 60;
        }

        return firstDayWorkMinutes + secondDayWorkMinutes + (workDayCount * fullDayWorkMinutes);
    }

    private static long calculateSingleDayWorkMinutes(LocalDateTime startTime, LocalDateTime endTime, boolean addLunchWorkHour) {
        // 如果是周末,返回0工时
        if (!isWorkDay(startTime) || !isWorkDay(endTime)) {
            return 0;
        }

        // 限制时间范围在工作时间内
        LocalTime start = startTime.toLocalTime().isBefore(WORK_START) ? WORK_START : startTime.toLocalTime();
        LocalTime end = endTime.toLocalTime().isAfter(WORK_END) ? WORK_END : endTime.toLocalTime();

        // 如果调整后的start时间比end时间大(跨天情况),则结束时间设为WORK_END
        if (start.isAfter(end)) {
            return  0;
        }

        Duration workDuration = Duration.between(start, end);

        // 如果addLunchWorkHour为false,并且工作时间和午休时间重叠,减去午休时间
        if (!addLunchWorkHour && start.isBefore(BREAK_END) && end.isAfter(BREAK_START)) {
            LocalTime breakStart = BREAK_START.isBefore(start) ? start : BREAK_START;
            LocalTime breakEnd = BREAK_END.isAfter(end) ? end : BREAK_END;

            // 只有在工作时间与午休时间重叠的情况下才减去午休时间
            if (breakStart.isBefore(breakEnd)) {
                Duration breakDuration = Duration.between(breakStart, breakEnd);
                workDuration = workDuration.minus(breakDuration);
            }
        }

        return workDuration.toMinutes();
    }

    // 判断是否是工作日(周一到周五)
    private static boolean isWorkDay(LocalDateTime dateTime) {
        DayOfWeek dayOfWeek = dateTime.getDayOfWeek();
        return dayOfWeek != DayOfWeek.SATURDAY && dayOfWeek != DayOfWeek.SUNDAY;
    }

工时按分钟计算:
修改后的方法 calculateWorkMinutes 计算总工时的分钟数,避免了之前只按小时计算而导致的精度问题。

跨天工作时间的计算:

第一天从 12:30 到 17:30:
总共 5 小时(300 分钟),减去午休时间 30 分钟,所以第一天的工时是 270 分钟。
第二天从 08:30 到 13:30:
08:30 到 12:00 是 3.5 小时(210 分钟),13:00 到 13:30 是 0.5 小时(30 分钟),合计为 240 分钟。
总计为 270 + 240 = 510 分钟,即 8.5 小时。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值