欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

计算工作日时长

程序员文章站 2022-03-03 10:14:35
...

计算工作日时长

工具类说明:

  • mapWorkDay 自定义节假日,主要针对国内每年制定发布的国内假日及补班时间,一般维护到数据库,每年更新一次,针对特殊日期标识【工作日】/【节假日】
  • dateUnit 时间计算精确单位,天/小时/分钟/秒等

代码:

package com.test.common.util;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.Week;
import com.test.common.constant.NumberConst;

import java.util.Date;
import java.util.Map;

public class DateUtilExt {

    /**
     * 工作日标志
     */
    private static final String WORK_DAY_FLAG_YES="1";
    /**
     * 非工作日标志
     */
    private static final String WORK_DAY_FLAG_NO="0";

    /**
     * 获取工作日时间
     * @param start 计算起始时间
     * @param end 计算结束时间
     * @param mapWorkDay 自定义节假日,例:<"2021-09-30","1"> 1-工作日,0-节假日
     * @param dateUnit 返回时间精确单位
     * @return
     */
    public static long getWorkDayTimes(Date start, Date end, Map<String, String> mapWorkDay, DateUnit dateUnit){
        if (start == null || end == null){
            return 0;
        }
        // 如果起始日期大于结束日期,替换位置
        if (DateUtil.compare(start, end) > 0){
            Date temp = start;
            start = end;
            end = temp;
        }

        if (!DateUtilExt.isWorkDay(start, mapWorkDay)){
            start = DateUtilExt.getNearestWorkDay(start, NumberConst.NUM_1, mapWorkDay);
        }
        if (!DateUtilExt.isWorkDay(end, mapWorkDay)){
            end = DateUtilExt.getNearestWorkDay(end, NumberConst.NUM_NEGATIVE_1, mapWorkDay);
        }

        if (DateUtil.compare(start, end) > 0){
            // 节假日间的,工作日耗时为0
            return 0;
        }

        if (DateUtil.formatDate(start).equals(DateUtil.formatDate(end))){
            // 如果是同一天,直接计算
            return DateUtil.between(start,end, dateUnit);
        }

        // 非同一天,总时长-节假日时长为工作日时长
        long totalTime = DateUtil.between(start, end, dateUnit);
        int holidayCount = 0;
        Date nextDay = DateUtil.offset(start, DateField.DAY_OF_YEAR, NumberConst.NUM_1);
        holidayCount = DateUtilExt.getHolidayCount(nextDay, end, holidayCount, mapWorkDay);
        long holidayTime = (holidayCount*DateUnit.DAY.getMillis())/dateUnit.getMillis();

        return totalTime-holidayTime;
    }

    /**
     * 获取时间范围内的假期天数,起始日期和结束日期均为工作日
     * @param currentDate 起始日期后一天
     * @param end
     * @param count
     * @param mapWorkDay
     */
    private static int getHolidayCount(Date currentDate, Date end, int count, Map<String, String> mapWorkDay){
        if (DateUtil.compare(currentDate, end) >= 0){
            return count;
        }
        if (!DateUtilExt.isWorkDay(currentDate, mapWorkDay)){
            count ++;
        }
        Date nextDay = DateUtil.offset(currentDate, DateField.DAY_OF_YEAR, NumberConst.NUM_1);
        return DateUtilExt.getHolidayCount(nextDay, end, count, mapWorkDay);
    }

    /**
     * 获取最近的工作日
     * @param date
     * @param forward 查找方向 1正向查找 -1反向查找
     * @param mapWorkDay 自定义节假日
     * @return
     */
    private static Date getNearestWorkDay(Date date, int forward, Map<String, String> mapWorkDay){
        if (DateUtilExt.isWorkDay(date, mapWorkDay)){
            return date;
        }
        Date nextDay = DateUtil.offset(date, DateField.DAY_OF_YEAR, forward);
        return DateUtilExt.getNearestWorkDay(nextDay, forward, mapWorkDay);
    }

    /**
     * 是否是工作日
     * @param date
     * @param mapWorkDay 自定义节假日
     * @return true-工作日 false-节假日
     */
    private static boolean isWorkDay(Date date, Map<String, String> mapWorkDay){
        if (!DateUtilExt.isWeekend(date)){
            // 工作日
            //判断是否有自定义假日
            if (mapWorkDay != null && WORK_DAY_FLAG_NO.equals(mapWorkDay.get(DateUtil.formatDate(date)))){
                // 自定义假日
                return false;
            }
            // 工作日
            return true;
        } else {
            // 节假日
            // 判断是否有自定义补班
            if (mapWorkDay != null && WORK_DAY_FLAG_YES.equals(mapWorkDay.get(DateUtil.formatDate(date)))){
                // 自定义补班
                return true;
            }
            // 节假日
            return false;
        }
    }

    /**
     * 是否是周末
     * @param date
     * @return
     */
    private static boolean isWeekend(Date date){
        Week currentWeek = DateUtil.dayOfWeekEnum(date);
        if (Week.SATURDAY.equals(currentWeek) || Week.SUNDAY.equals(currentWeek)){
            return true;
        }
        return false;
    }
}