前提:业务场景  最近公司业务中需要根据一段时间内 根据工作日去筛选计算一个完整周期时长 超时情况分为以下四种(正常,即将到期,延误,严重延误)简单实现 非礼勿喷

两种实现:

1.第一种是 计算     根据传入  时间戳 加上指定天数 得出最终结束日时间戳(不计入周末时间 前者   后者顺延)  


2.第二种是 计算     两个时间戳 相差工作日 毫秒数 (不计入周末时间 前者  后者顺延)  


准备条件: 需要有一张日历维护表 维护 年数据

CREATE TABLE `calendar_day` (
   `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID主键,自增',
   `date_time` int(10) DEFAULT NULL COMMENT '具体日期',
   `date_flag` int(4) DEFAULT NULL COMMENT '类型标识码表(CBPMDateType)',
   `remark` varchar(255) DEFAULT NULL COMMENT '备注',
   `create_ti` bigint(13) DEFAULT NULL COMMENT '创建时间',
   `create_user_id` int(11) DEFAULT NULL COMMENT '创建者',
   `modify_ti` bigint(13) DEFAULT NULL COMMENT '修改时间',
   `modify_user_id` int(11) DEFAULT NULL COMMENT '修改者',
   `version` int(11) DEFAULT '0' COMMENT '版本默认为0,-1为删除',
   PRIMARY KEY (`id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=804 DEFAULT CHARSET=utf8 COMMENT='日历表';


当前 注意的类型码表标识 项目喜欢 使用通过 码表标识 常用记录问题  所以单独解释下  当前类型对应 一下四个值 标识节假日及其上班

CBPMDateType

1001

正常工作日

1002

节假日上班

2001

正常节假日

2002

工作日休息



第一种实现 (加上工作日计算):

逻辑  : 当前 是工作日直接计算 ,如果是休息日 则取最近一个工作日计算(往后推),参数解释:1.开始时间毫秒数  2.相加天数


public Long selectDateAdd(Long startDay, int days) {
         logger.info("selectDateAdd  startDay=={},  days=={}", startDay, days);
         Map<String, Object> paraMap = new HashMap<String, Object>();
         String startDayStr = DateUtil.timestamp2String(startDay, "yyyyMMdd HH:ss:mm");
         paraMap.put("startDay", Integer.valueOf(startDayStr.substring(0, 8)) - 1);
         paraMap.put("days", days-1);
         CalendarDay calendarDay = calendarDayMapper.selectDateAdd(paraMap);
         if (null == calendarDay) {
             logger.info("暂无维护日期");
             return startDay + (long) days * 24 * 60 * 60 * 1000;
         }
         CalendarDay startDayCalendarDay = calendarDayMapper
             .selectByDate(Integer.valueOf(startDayStr.substring(0, 8)));
         String endDayStr;
         if (startDayCalendarDay != null) {


             if (startDayCalendarDay.getDateFlag()
                 .intValue() == CBpmConstant.CBPM_DATA_TIME_TYPE_1001
                 || startDayCalendarDay.getDateFlag()
                     .intValue() == CBpmConstant.CBPM_DATA_TIME_TYPE_1002) {
                 //开始日上班
                 logger.info("开始日上班");
                 endDayStr = calendarDay.getDateTime().toString() + startDayStr.substring(8);
             } else {
                 //开始日不上班
                 logger.info("开始日不上班");
                 endDayStr = calendarDay.getDateTime().toString() + " 23:59:59";
             }
             return DateUtil.string2Timestamp(endDayStr, "yyyyMMdd HH:ss:mm");
         } else {
             return startDay + (long) days * 24 * 60 * 60 * 1000;
         }
     }

第二种实现:计算 两个时间戳 相差工作日 毫秒数 

逻辑 :    参数 1.开始时间戳  2.结束时间戳

public Long selectDateDiff(Long startDay, Long endDay) {
         logger.debug("startDay {} , endDay {}",startDay,endDay);
         CalendarDay startDayCalendarDay = calendarDayMapper.selectByDate(Integer
             .valueOf(DateUtil.timestamp2String(startDay, "yyyyMMdd HH:ss:mm").substring(0, 8)));
         CalendarDay endDayCalendarDay = calendarDayMapper.selectByDate(Integer
             .valueOf(DateUtil.timestamp2String(endDay, "yyyyMMdd HH:ss:mm").substring(0, 8)));
         if (null == startDayCalendarDay || endDayCalendarDay == null) {
             logger.info("暂无维护日期");
             return endDay - startDay;
         }
         Long startSec = 0l;//开始那天剩余毫秒数
         Long endSec = 0l;//结束那天剩余毫秒数
         Integer startDayInter = Integer
             .valueOf(DateUtil.timestamp2String(startDay, "yyyyMMdd HH:ss:mm").substring(0, 8));
         Integer endDayInter = Integer
             .valueOf(DateUtil.timestamp2String(endDay, "yyyyMMdd HH:ss:mm").substring(0, 8));
         if (startDayInter.intValue() == endDayInter.intValue()) {
             //开始结束是同一天
             if (startDayCalendarDay.getDateFlag()
                 .intValue() == CBpmConstant.CBPM_DATA_TIME_TYPE_1001
                 || startDayCalendarDay.getDateFlag()
                     .intValue() == CBpmConstant.CBPM_DATA_TIME_TYPE_1002) {
                 logger.info("开始结束是同一天  上班");
                 return endDay - startDay;
             } else {
                 logger.info("开始结束是同一天  休息");
                 return 0l;
             }
         }


         if (startDayCalendarDay.getDateFlag().intValue() == CBpmConstant.CBPM_DATA_TIME_TYPE_1001
             || startDayCalendarDay.getDateFlag()
                 .intValue() == CBpmConstant.CBPM_DATA_TIME_TYPE_1002) {
             //开始日上班
             logger.info("开始日上班");
         } else {
             //开始日休息
             logger.info("开始日休息");
             String startDayEndStr = startDayInter.toString() + " 23:59:59";
             startSec = DateUtil.string2Timestamp(startDayEndStr, "yyyyMMdd HH:ss:mm") - startDay;
         }     


         if (endDayCalendarDay.getDateFlag().intValue() == CBpmConstant.CBPM_DATA_TIME_TYPE_1001
             || endDayCalendarDay.getDateFlag()
                 .intValue() == CBpmConstant.CBPM_DATA_TIME_TYPE_1002) {
             //结束日上班
             logger.info("结束日上班");
         } else {
             //结束日休息
             logger.info("结束日休息");
             endSec = endDay - DateUtil.string2Timestamp(endDayInter.toString() + " 00:00:00",
                 "yyyyMMdd HH:ss:mm");
         }
         Map<String, Object> paraMap = new HashMap<String, Object>();
         paraMap.put("startDay", startDayInter);
         paraMap.put("endDay", endDayInter);
         Long days = calendarDayMapper.selectDateDiff(paraMap);
         return endDay - startDay - startSec - endSec - (long) days * 24 * 60 * 60 * 1000;
     }

备注 :

 最后位置 计算方便理解:

开始时间 -结束时间 -休息时间到23.59.59 -结束到0.0.0-两者相距的工作日*毫秒数


备注:

相关sql 仅供参考

/**
      * 获取一个内的所有节假日数据
      * @param month
      * @return
      */
     List<CalendarDay> selectListMonth(String month);


     /**
      * @param paraMap
      * @return  工作日加法
      */
     CalendarDay selectDateAdd(Map<String, Object> paraMap);


     /**查询当日情况
      * @param startDay
      * @return
      */
     CalendarDay selectByDate(Integer startDay);


     /**统计日期差工作日
      * @param paraMap
      * @return
      */
     Long selectDateDiff(Map<String, Object> paraMap);
 <select id="selectListMonth" parameterType="java.lang.String" resultMap="BaseResultMap" >
    SELECT 
cd.*
from cbpm.calendar_day cd 
where SUBSTR(cd.date_time FROM 1 FOR 6) =  #{month,jdbcType=INTEGER}
    </select>

    <select id="selectDateAdd" parameterType="java.util.Map" resultMap="BaseResultMap" >
SELECT 
<include refid="Base_Column_List" />
FROM calendar_day cd 
where cd.date_flag in (${@com.jsb.cbpm.common.CBpmConstant@CBPM_DATA_TIME_TYPE_1001},
${@com.jsb.cbpm.common.CBpmConstant@CBPM_DATA_TIME_TYPE_1002})
and cd.date_time > #{startDay,jdbcType=INTEGER}
 ORDER BY date_time asc limit #{days,jdbcType=INTEGER},1
    </select>
    <select id="selectByDate" parameterType="java.lang.Integer" resultMap="BaseResultMap" >
SELECT 
<include refid="Base_Column_List" />
FROM calendar_day cd 
where  cd.date_time = #{startDay,jdbcType=INTEGER} limit 1
    </select>
    
    
<select id="selectDateDiff" parameterType="java.util.Map" resultType="java.lang.Long" >
SELECT count(*) 
FROM calendar_day cd 
where   cd.date_flag in (${@com.jsb.cbpm.common.CBpmConstant@CBPM_DATA_TIME_TYPE_2001},
${@com.jsb.cbpm.common.CBpmConstant@CBPM_DATA_TIME_TYPE_2002})
and cd.date_time > #{startDay,jdbcType=INTEGER} 
and #{endDay,jdbcType=INTEGER} > cd.date_time
    </select>


当前引用到一些封装的日期工具类,可以参考链接去看下