目的:用来计算两个日期之间的工作时长
说明:其中节假日、工作日工作时间需要从配置表中获取
直接上代码
public static void main(String[] args) throws Exception {calTime("2023-09-23 07:30:00", "2023-09-25 18:30:05");}/*** 计算两个日期间的工作时长** @param begintime yyyy-MM-dd HH:mm:ss* @param endTime yyyy-MM-dd HH:mm:ss* @return 工作时长/毫秒*/public static long calTime(String begintime, String endTime) {Date startDate = DateUtil.parse(begintime);//节点到达时间Date endDate = DateUtil.parse(endTime);//当前时间int compareNum = DateUtil.compare(startDate, endDate);if (compareNum > 0) {String temp = endTime;endTime = begintime;begintime = temp;}startDate = DateUtil.parse(begintime);//节点到达时间endDate = DateUtil.parse(endTime);//当前时间System.out.println("计算前-hours-" + (((DateUtil.between(startDate, endDate, DateUnit.MS) * 1.0 / 3600000) - 3) > 0));long millis = DateUtil.between(startDate, endDate, DateUnit.MS);System.out.println("计算前-millis-" + millis);System.out.println("计算前-" + DateUtil.formatBetween(millis, BetweenFormater.Level.SECOND));//开始日期当天String beginDateStr = DateUtil.format(DateUtil.parse(begintime), "yyyy-MM-dd");String beginTimeStr = DateUtil.format(DateUtil.parse(begintime), "HH:mm:ss");//截止日期当天String endDateStr = DateUtil.format(DateUtil.parse(endTime), "yyyy-MM-dd");String endTimeStr = DateUtil.format(DateUtil.parse(endTime), "HH:mm:ss");long subMills = 0;//需要减去的时长Map<String, Map<String, String>> workDayInfoMap = initWorkdayInfo();// 同一天if (beginDateStr.equals(endDateStr)) {if (isWorkingDay(beginDateStr)) {//工作日long tempMills = calWorkDayRestMills(workDayInfoMap, beginDateStr, beginTimeStr, endTimeStr);subMills += tempMills;} else {subMills = millis;//同一天且非工作日}} else {long daysLen = DateUtil.between(DateUtil.parse(beginDateStr), DateUtil.parse(endDateStr), DateUnit.DAY, false);//相差天数//处理开始日期if (isWorkingDay(beginDateStr)) {long tempMills = calWorkDayRestMills(workDayInfoMap, beginDateStr, beginTimeStr, "23:59:59") + 1000;subMills += tempMills;} else {long tempMills = DateUtil.between(DateUtil.parse(begintime), DateUtil.parse(beginDateStr + " 23:59:59"), DateUnit.MS) + 1000;subMills += tempMills;}//处理中间日期if (daysLen > 1) {for (int i = 1; i < daysLen; i++) {String tempDateStr = DateUtil.format(DateUtil.offsetDay(DateUtil.parse(begintime), i), "yyyy-MM-dd");if (isWorkingDay(tempDateStr)) {long tempMills = calWorkDayRestMills(workDayInfoMap, tempDateStr, "00:00:00", "23:59:59") + 1000;subMills += tempMills;} else {long tempMills = DateUtil.between(DateUtil.parse(tempDateStr + " 00:00:00"), DateUtil.parse(tempDateStr + " 23:59:59"), DateUnit.MS) + 1000;subMills += tempMills;}}}//处理截止日期if (isWorkingDay(endDateStr)) {long tempMills = calWorkDayRestMills(workDayInfoMap, endDateStr, "00:00:00", endTimeStr);//工时长subMills += tempMills;} else {long tempMills = DateUtil.between(DateUtil.parse(endDateStr + " 00:00:00"), DateUtil.parse(endTime), DateUnit.MS);subMills += tempMills;}}System.out.println("计算后-subMills-" + subMills);millis = millis - subMills;System.out.println("计算后-millis-" + millis);System.out.println("计算后-" + DateUtil.formatBetween(millis, BetweenFormater.Level.SECOND));return millis;}/*** 计算工作日,开始时间--截止时间知之间的非工作日时间长【日期是同一天,且是工作日】** @param workDayInfoMap 工作日工作时间信息* @param dateStr yyyy-MM-dd* @param beginTimeStr HH:mm:ss* @param endTimeStr HH:mm:ss* @return*/private static Long calWorkDayRestMills(Map<String, Map<String, String>> workDayInfoMap, String dateStr, String beginTimeStr, String endTimeStr) {if (workDayInfoMap == null || workDayInfoMap.size() == 0|| dateStr == null || beginTimeStr == null || endTimeStr == null) {return null;}//step1:判断时间大小Integer hourB = DateUtil.hour(DateUtil.parse(beginTimeStr), true);Integer hourE = DateUtil.hour(DateUtil.parse(endTimeStr), true);if (hourB > hourE) {String temp = endTimeStr;endTimeStr = beginTimeStr;beginTimeStr = temp;}//step2:获取两个时间的时间差,单位毫秒long allMills = DateUtil.between(DateUtil.parse(dateStr + " " + beginTimeStr), DateUtil.parse(dateStr + " " + endTimeStr), DateUnit.MS);System.out.println("计算中-allMills-" + allMills);long workMills1 = 0;long workMills2 = 0;//step3:获取月份及工作日信息Integer month = 1 + DateUtil.month(DateUtil.parse(dateStr));//DateUtil.month从0开始算String monthStr = String.valueOf(month);if (month < 10) {monthStr = "0" + month;}Map<String, String> workInfo = workDayInfoMap.get(monthStr);if (workInfo == null) {return null;}String amBegin = workInfo.get("amBegin");String amEnd = workInfo.get("amEnd");String pmBegin = workInfo.get("pmBegin");String pmEnd = workInfo.get("pmEnd");//step4:开始时间、结束时间和工作日时间对比int bcr1 = DateUtil.compare(DateUtil.parse(beginTimeStr), DateUtil.parse(amBegin));//1表示前面大,0相等,-1表示前面小int bcr2 = DateUtil.compare(DateUtil.parse(beginTimeStr), DateUtil.parse(amEnd));int bcr3 = DateUtil.compare(DateUtil.parse(beginTimeStr), DateUtil.parse(pmBegin));int bcr4 = DateUtil.compare(DateUtil.parse(beginTimeStr), DateUtil.parse(pmEnd));int ecr1 = DateUtil.compare(DateUtil.parse(endTimeStr), DateUtil.parse(amBegin));int ecr2 = DateUtil.compare(DateUtil.parse(endTimeStr), DateUtil.parse(amEnd));int ecr3 = DateUtil.compare(DateUtil.parse(endTimeStr), DateUtil.parse(pmBegin));int ecr4 = DateUtil.compare(DateUtil.parse(endTimeStr), DateUtil.parse(pmEnd));//step4:获取工作时长if (bcr1 < 0) {//上午上班前if (ecr1 < 0) {//上午上班前--无需处理} else if (ecr1 >= 0 && ecr2 < 0) {//上午上班区间workMills1 = DateUtil.between(DateUtil.parse(dateStr + " " + amBegin), DateUtil.parse(dateStr + " " + endTimeStr), DateUnit.MS);} else if (ecr2 >= 0 && ecr3 < 0) {//中午休息区间workMills1 = DateUtil.between(DateUtil.parse(dateStr + " " + amBegin), DateUtil.parse(dateStr + " " + amEnd), DateUnit.MS);} else if (ecr3 >= 0 && ecr4 < 0) {//下午上班区间workMills1 = DateUtil.between(DateUtil.parse(dateStr + " " + amBegin), DateUtil.parse(dateStr + " " + amEnd), DateUnit.MS);workMills2 = DateUtil.between(DateUtil.parse(dateStr + " " + pmBegin), DateUtil.parse(dateStr + " " + endTimeStr), DateUnit.MS);} else if (ecr4 >= 0) {//下午下班时间workMills1 = DateUtil.between(DateUtil.parse(dateStr + " " + amBegin), DateUtil.parse(dateStr + " " + amEnd), DateUnit.MS);workMills2 = DateUtil.between(DateUtil.parse(dateStr + " " + pmBegin), DateUtil.parse(dateStr + " " + pmEnd), DateUnit.MS);}} else if (bcr1 >= 0 && bcr2 < 0) {//上午上班区间if (ecr1 >= 0 && ecr2 < 0) {//上午上班区间workMills1 = DateUtil.between(DateUtil.parse(dateStr + " " + beginTimeStr), DateUtil.parse(dateStr + " " + endTimeStr), DateUnit.MS);} else if (ecr2 >= 0 && ecr3 < 0) {//中午休息区间workMills1 = DateUtil.between(DateUtil.parse(dateStr + " " + beginTimeStr), DateUtil.parse(dateStr + " " + amEnd), DateUnit.MS);} else if (ecr3 >= 0 && ecr4 < 0) {//下午上班区间workMills1 = DateUtil.between(DateUtil.parse(dateStr + " " + beginTimeStr), DateUtil.parse(dateStr + " " + amEnd), DateUnit.MS);workMills2 = DateUtil.between(DateUtil.parse(dateStr + " " + pmBegin), DateUtil.parse(dateStr + " " + endTimeStr), DateUnit.MS);} else if (ecr4 >= 0) {//下午下班时间workMills1 = DateUtil.between(DateUtil.parse(dateStr + " " + beginTimeStr), DateUtil.parse(dateStr + " " + amEnd), DateUnit.MS);workMills2 = DateUtil.between(DateUtil.parse(dateStr + " " + pmBegin), DateUtil.parse(dateStr + " " + pmEnd), DateUnit.MS);}} else if (bcr2 >= 0 && bcr3 < 0) {//中午休息区间if (ecr2 >= 0 && ecr3 < 0) {//中午休息区间--无需处理} else if (ecr3 >= 0 && ecr4 < 0) {//下午上班区间workMills2 = DateUtil.between(DateUtil.parse(dateStr + " " + pmBegin), DateUtil.parse(dateStr + " " + endTimeStr), DateUnit.MS);} else if (ecr4 >= 0) {//下午下班时间workMills2 = DateUtil.between(DateUtil.parse(dateStr + " " + pmBegin), DateUtil.parse(dateStr + " " + pmEnd), DateUnit.MS);}} else if (bcr3 >= 0 && bcr4 < 0) {//下午上班区间if (ecr3 >= 0 && ecr4 < 0) {//下午上班区间workMills2 = DateUtil.between(DateUtil.parse(dateStr + " " + beginTimeStr), DateUtil.parse(dateStr + " " + endTimeStr), DateUnit.MS);} else if (ecr4 >= 0) {//下午下班时间workMills2 = DateUtil.between(DateUtil.parse(dateStr + " " + beginTimeStr), DateUtil.parse(dateStr + " " + pmEnd), DateUnit.MS);}} else if (bcr4 >= 0) {//下午下班时间--无需处理}System.out.println("计算中-workMills1-" + workMills1);System.out.println("计算中-workMills2-" + workMills2);long noWorkMills = allMills - workMills1 - workMills2;System.out.println("计算中-(allMills - workMills1 - workMills2)-" + noWorkMills);return noWorkMills;}/*** 判断是否为工作日** @param dateStr yyyy-MM-dd* @return*/public static Boolean isWorkingDay(String dateStr) {List<String> holiday = initHoliday();List<String> extraWorkDay = initExtraWorkDay();//补班日if (extraWorkDay.contains(dateStr)) {return true;}//节假日if (holiday.contains(dateStr)) {return false;}//hutool工具jar,5.3.0版本【1是工作日,2-7表示周一到周六】int week = DateUtil.dayOfWeek(DateUtil.parse(dateStr));if (week == 1 || week == 7) {return false;//周末}return true;}/*** 初始化节假日【生产环境中请使用配置表】* 可通过接口获取每年节假日保存到配置表【文档--https://timor.tech/api/holiday】* String url = "https://timor.tech/api/holiday/year/2023/";* String rsa = HttpUtil.get(url);** @return*/public static List<String> initHoliday() {List<String> holiday = new ArrayList<>();holiday.add("2023-01-28");holiday.add("2023-12-31");holiday.add("2023-10-06");holiday.add("2023-10-05");holiday.add("2023-10-04");holiday.add("2023-10-03");holiday.add("2023-10-02");holiday.add("2023-10-01");holiday.add("2023-09-30");holiday.add("2023-09-29");holiday.add("2023-06-24");holiday.add("2023-06-23");holiday.add("2023-06-22");holiday.add("2023-05-03");holiday.add("2023-05-02");holiday.add("2023-05-01");holiday.add("2023-04-30");holiday.add("2023-04-29");holiday.add("2023-04-05");holiday.add("2023-01-27");holiday.add("2023-01-26");holiday.add("2023-01-25");holiday.add("2023-01-24");holiday.add("2023-01-23");holiday.add("2023-01-22");holiday.add("2023-01-21");holiday.add("2023-01-02");holiday.add("2023-01-01");return holiday;}/*** 初始化额外加班日【生产环境中请使用配置表】* 可通过接口获取每年节假日保存到配置表【文档--https://timor.tech/api/holiday】* String url = "https://timor.tech/api/holiday/year/2023/";** @return*/public static List<String> initExtraWorkDay() {List<String> extraWorkDay = new ArrayList<>();extraWorkDay.add("2023-10-08");extraWorkDay.add("2023-10-07");extraWorkDay.add("2023-06-25");extraWorkDay.add("2023-05-06");extraWorkDay.add("2023-04-23");extraWorkDay.add("2023-01-29");extraWorkDay.add("2023-01-28");return extraWorkDay;}/*** 初始化工作日工作时间【生产环境中请使用配置表】** @return*/public static Map<String, Map<String, String>> initWorkdayInfo() {Map<String, Map<String, String>> workDayInfoMap = new HashMap<>();//冬令时Map<String, String> map = new HashMap<>();map.put("amBegin", "08:00:00");map.put("amEnd", "12:00:00");map.put("pmBegin", "14:00:00");map.put("pmEnd", "17:30:00");workDayInfoMap.put("10", map);workDayInfoMap.put("11", map);workDayInfoMap.put("12", map);workDayInfoMap.put("01", map);workDayInfoMap.put("02", map);workDayInfoMap.put("03", map);workDayInfoMap.put("04", map);//夏令时map = new HashMap<>();map.put("amBegin", "08:00:00");map.put("amEnd", "12:00:00");map.put("pmBegin", "14:30:00");map.put("pmEnd", "18:00:00");workDayInfoMap.put("05", map);workDayInfoMap.put("06", map);workDayInfoMap.put("07", map);workDayInfoMap.put("08", map);workDayInfoMap.put("09", map);return workDayInfoMap;}