Java时间去掉节假日周末计算工作时间的方式

记录一下根据时间区间计算工作时间,同时去掉节假日周六日

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 工作时间计算
 *
 * @author
 * @description:
 * @date
 */
public class WorkTimeCalculate {
    /**
     * 上班时间
     */
    private static final LocalTime WORKING_START_TIME = LocalTime.of(9, 0);
    /**
     * 下班时间
     */
    private static final LocalTime WORKING_END_TIME = LocalTime.of(17, 0);
    /**
     * 午休开始时间
     */
    private static final LocalTime NOON_BREAK_START_TIME = LocalTime.of(12, 0);
    /**
     * 午休结束时间
     */
    private static final LocalTime NOON_BREAK_END_TIME = LocalTime.of(14, 0);
    /**
     * 调休日:非周末但是休息的日期列表
     */
    private static final List<LocalDate> holidays = new ArrayList<>();
    /**
     * 补班日:周末但是上班的日期
     */
    private static final List<LocalDate> workdays = new ArrayList();

    //初始化调休日和补班日   后面可考虑从数据库查
    static {
        //调休日
        holidays.add(LocalDate.of(2022, 1, 3));
        holidays.add(LocalDate.of(2022, 1, 31));
        holidays.add(LocalDate.of(2022, 2, 1));
        holidays.add(LocalDate.of(2022, 2, 2));
        holidays.add(LocalDate.of(2022, 2, 3));
        holidays.add(LocalDate.of(2022, 2, 4));
        holidays.add(LocalDate.of(2022, 4, 4));
        holidays.add(LocalDate.of(2022, 4, 5));
        holidays.add(LocalDate.of(2022, 5, 2));
        holidays.add(LocalDate.of(2022, 5, 3));
        holidays.add(LocalDate.of(2022, 5, 4));
        holidays.add(LocalDate.of(2022, 6, 3));
        holidays.add(LocalDate.of(2022, 9, 12));
        holidays.add(LocalDate.of(2022, 10, 3));
        holidays.add(LocalDate.of(2022, 10, 4));
        holidays.add(LocalDate.of(2022, 10, 5));
        holidays.add(LocalDate.of(2022, 10, 6));
        holidays.add(LocalDate.of(2022, 10, 7));

        holidays.add(LocalDate.of(2023, 1, 2));
        holidays.add(LocalDate.of(2023, 1, 23));
        holidays.add(LocalDate.of(2023, 1, 24));
        holidays.add(LocalDate.of(2023, 1, 25));
        holidays.add(LocalDate.of(2023, 1, 26));
        holidays.add(LocalDate.of(2023, 1, 27));
        holidays.add(LocalDate.of(2023, 4, 5));
        holidays.add(LocalDate.of(2023, 5, 1));
        holidays.add(LocalDate.of(2023, 5, 2));
        holidays.add(LocalDate.of(2023, 5, 3));
        holidays.add(LocalDate.of(2023, 6, 22));
        holidays.add(LocalDate.of(2023, 6, 23));
        holidays.add(LocalDate.of(2023, 9, 29));
        holidays.add(LocalDate.of(2023, 10, 2));
        holidays.add(LocalDate.of(2023, 10, 3));
        holidays.add(LocalDate.of(2023, 10, 4));
        holidays.add(LocalDate.of(2023, 10, 5));
        holidays.add(LocalDate.of(2023, 10, 6));
        //补班日
        workdays.add(LocalDate.of(2022, 1, 29));
        workdays.add(LocalDate.of(2022, 1, 30));
        workdays.add(LocalDate.of(2022, 4, 2));
        workdays.add(LocalDate.of(2022, 4, 24));
        workdays.add(LocalDate.of(2022, 5, 7));
        workdays.add(LocalDate.of(2022, 10, 8));
        workdays.add(LocalDate.of(2022, 10, 9));

        workdays.add(LocalDate.of(2023, 1, 28));
        workdays.add(LocalDate.of(2023, 1, 29));
        workdays.add(LocalDate.of(2023, 4, 23));
        workdays.add(LocalDate.of(2023, 5, 6));
        workdays.add(LocalDate.of(2023, 6, 25));
        workdays.add(LocalDate.of(2023, 10, 7));
        workdays.add(LocalDate.of(2023, 10, 8));
    }


    public static BigDecimal getWorkTime(LocalDateTime startDateTime, LocalDateTime endDateTime,List<LocalDate> holidays,List<LocalDate> workdays) {
        if (startDateTime.compareTo(endDateTime) > 0) {
            throw new RuntimeException("参数错误,开始时间大于结束时间。");
        }
        int diff = 0;

        while (true) {
            //休息日   开始时间后移至第二天的开始工作时间
            while (needPass(startDateTime,holidays,workdays)) {
                startDateTime = LocalDateTime.of(startDateTime.toLocalDate(), WORKING_START_TIME).plusDays(1);
            }

            //休息日   结束时间后移至第二天的开始工作时间
            while (needPass(endDateTime,holidays,workdays)) {
                endDateTime = LocalDateTime.of(endDateTime.toLocalDate(), WORKING_START_TIME).plusDays(1);
            }

            // 跨天处理
            if (startDateTime.getDayOfYear() == endDateTime.getDayOfYear()) {
                int diffSecond = getDiffSecond(startDateTime, endDateTime);
                diff = diffSecond + diff;
                break;
            }
            int diffSecond = getDiffSecond(startDateTime, LocalDateTime.of(startDateTime.toLocalDate(), WORKING_END_TIME));
            diff = diffSecond + diff;
            startDateTime = LocalDateTime.of(startDateTime.toLocalDate(), WORKING_START_TIME).plusDays(1);
        }
        BigDecimal day = new BigDecimal(diff).divide(new BigDecimal(6 * 60*60), 2, RoundingMode.HALF_UP);

//        System.out.println("DIFF(hours): " + day+ "天");
        return day;
    }

    private static int getDiffSecond(LocalDateTime startDateTime, LocalDateTime endDateTime) {
        LocalTime startTime = startDateTime.toLocalTime();
        LocalTime endTime = endDateTime.toLocalTime();
        // diff单位:秒
        int diff = 0;

        // 开始时间切移
        if (startTime.isBefore(WORKING_START_TIME)) {
            startTime = WORKING_START_TIME;
        } else if (startTime.isAfter(NOON_BREAK_START_TIME) && startTime.isBefore(NOON_BREAK_END_TIME)) {
            startTime = NOON_BREAK_START_TIME;
        } else if (startTime.isAfter(WORKING_END_TIME)) {
            startTime = WORKING_END_TIME;
        }
        // 结束时间切移
        if (endTime.isBefore(WORKING_START_TIME)) {
            endTime = WORKING_START_TIME;
        } else if (endTime.isAfter(NOON_BREAK_START_TIME) && endTime.isBefore(NOON_BREAK_END_TIME)) {
            endTime = NOON_BREAK_START_TIME;
        } else if (endTime.isAfter(WORKING_END_TIME)) {
            endTime = WORKING_END_TIME;
        }
        // 午休时间判断处理
        if (startTime.compareTo(NOON_BREAK_START_TIME) <= 0 && endTime.compareTo(NOON_BREAK_END_TIME) >= 0) {
            diff = diff + (NOON_BREAK_END_TIME.toSecondOfDay()-NOON_BREAK_START_TIME.toSecondOfDay());
        }
        diff = endTime.toSecondOfDay() - startTime.toSecondOfDay() - diff;

        return diff;
    }


    /**
     * 计算两个时间之间的天数   每天按24小数计算  不考虑上下班  不足一天的部分保留两位小数
     * 特殊情况:开始时间在休息日,则开始时间按下个工作日的00:00:00开始计算
     * 特殊情况:结束时间在休息日,则结束时间按上个工作日的13:59:59开始计算
     *
     * @param startDateTime
     * @param endDateTime
     * @return
     */
    public static BigDecimal getWorkDays(LocalDateTime startDateTime, LocalDateTime endDateTime,List<LocalDate> holidays,List<LocalDate> workdays) {
        if (startDateTime.compareTo(endDateTime) > 0) {
            throw new RuntimeException("参数错误,开始时间大于结束时间。");
        }
        int fullDays = 0;
        long minute = 0;
        //特殊情况:开始时间在休息日,则开始时间按下个工作日的00:00:00开始计算
        if (needPass(startDateTime,holidays,workdays)) {
            startDateTime = startDateTime.toLocalDate().atStartOfDay().plusDays(1);
        }
        //特殊情况:结束时间在休息日,则结束时间按上个工作日的13:59:59开始计算
        if (needPass(endDateTime,holidays,workdays)) {
            endDateTime = endDateTime.toLocalDate().atStartOfDay();
        }

        while (startDateTime.compareTo(endDateTime) < 0) {
            while (needPass(startDateTime,holidays,workdays)) {
                startDateTime = startDateTime.plusDays(1);
            }
            while (needPass(endDateTime,holidays,workdays)) {
                endDateTime = endDateTime.plusDays(1);
            }
            if (startDateTime.getDayOfYear() == endDateTime.getDayOfYear()) {
                // 按分钟计算
                minute = Duration.between(startDateTime, endDateTime).toMinutes();
                break;
            }

            startDateTime = startDateTime.plusDays(1);
            fullDays += 1;
        }
        //折算不足一天的时间
        BigDecimal oddDay = new BigDecimal(minute).divide(new BigDecimal(8 * 60), 2, RoundingMode.HALF_UP);

        return new BigDecimal(fullDays).add(oddDay);
    }
    public static BigDecimal getWorkDays(LocalDateTime startDateTime, LocalDateTime endDateTime) {
        if (startDateTime.compareTo(endDateTime) > 0) {
            throw new RuntimeException("参数错误,开始时间大于结束时间。");
        }
        int fullDays = 0;
        long minute = 0;

        while (startDateTime.compareTo(endDateTime) < 0) {
            if (startDateTime.getDayOfYear() == endDateTime.getDayOfYear()) {
                // 按分钟计算
                minute = Duration.between(startDateTime, endDateTime).toMinutes();
                break;
            }

            startDateTime = startDateTime.plusDays(1);
            fullDays += 1;
        }
        //折算不足一天的时间
        BigDecimal oddDay = new BigDecimal(minute).divide(new BigDecimal(24 * 60), 2, RoundingMode.HALF_UP);

        return new BigDecimal(fullDays).add(oddDay);
    }


    /**
     * 当天休息还是工作
     *
     * @param time
     * @return
     */
    private static boolean needPass(LocalDateTime time,List<LocalDate> holidays,List<LocalDate> workdays) {
        if (time.getDayOfWeek() == DayOfWeek.SATURDAY || time.getDayOfWeek() == DayOfWeek.SUNDAY) {
            if (isWorkday(time,workdays)) {
                return false;
            }
            return true;
        } else {
            if (isHoliday(time,holidays)) {
                return true;
            }
            return false;
        }
    }

    /**
     * 是否调休日
     *
     * @param time
     * @return
     */
    private static boolean isHoliday(LocalDateTime time,List<LocalDate> holidays) {
        LocalDate date = time.toLocalDate();
        if (holidays.contains(date)) {
            return true;
        }
        return false;
    }

    /**
     * 是否补班日
     *
     * @param time
     * @return
     */
    private static boolean isWorkday(LocalDateTime time, List<LocalDate> workdays) {
        LocalDate date = time.toLocalDate();
        if (workdays.contains(date)) {
            return true;
        }
        return false;
    }


    public static void main(String[] args) {
        LocalDateTime startDateTime= LocalDateTime.of(2024, 6, 28, 9, 0, 0);
        LocalDateTime endDateTime= LocalDateTime.of(2024, 6, 28, 12, 0, 0);

        WorkTimeCalculate.getWorkTime(startDateTime,endDateTime, new ArrayList<>(), new ArrayList<>());
        System.out.println(WorkTimeCalculate.getWorkDays(startDateTime,endDateTime, new ArrayList<>(), new ArrayList<>()));
        LocalDateTime date1 = LocalDateTime.of(2024, 6, 1,0, 00, 0);
        LocalDateTime date2 = LocalDateTime.of(2024, 6, 30,23, 59, 59);
        System.out.println(WorkTimeCalculate.getWorkDays(date1,date2));
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值