前提:业务场景 最近公司业务中需要根据一段时间内 根据工作日去筛选计算一个完整周期时长 超时情况分为以下四种(正常,即将到期,延误,严重延误)简单实现 非礼勿喷
两种实现:
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>
当前引用到一些封装的日期工具类,可以参考链接去看下