新进入一家公司,工资涨了一点点,忙了起来,自己也遇到很多事情,现在算是刚刚处理完,有心情开始写点博客了。现在的公司算是我前前任公司,我都怀疑我会不会在两家公司反复横跳,现在算是以开发的身份在公司做项目,很不幸,我又加入了一家以项目主的公司,当问起我接不接受出差的时候,我还是接受了出差,所以我现在是经常在出差。
新项目有个需求,以接收“单子”时间起,倒计时十五个工作日,做计算提醒,也就是说,这个数字每天都会减小,还要排除工作日,计算很好解决,如何排除非工作日?
1、调用外部接口获取非工作日的日期
2、本地数据库存储非工作日
我想都没想,就使用的第二个方案,因为我们的项目都不会联网,所以调用外部接口是不现实的。
解决思路:接收时间加15天-当前时间=还剩多少时间
其中接收时间加15天的时候,要判断在这15天里,有多少天是非工作日,有几天则加几天,也就是说,接收时间+15+N天才是最终时间。
我新建了一张表,用于存储非工作日,其实法定节假日就那么几天,所以我的想法是,存所有的周六日,然后手动修改法定节假日,也就是手动“维护”当年的劳动节、国庆节、中秋节等等。
MySQL
CREATE TABLE `non_or_working_day` ( `DAY_TITLE` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '今日命题', `NON_WORKING_DATE` datetime NULL DEFAULT NULL COMMENT '非工作日期', `REMARK` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注', `CREATE_TIME` datetime NULL DEFAULT NULL COMMENT '创建时间', `UPDATE_TIME` datetime NULL DEFAULT NULL COMMENT '修改时间', `ID` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '主键', PRIMARY KEY (`ID`) USING BTREE) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
使用 Java 生成当年所有的周六日
public static void main(String[] args) { int year = 2021; List<String> dateList=new ArrayList<String>(); SimpleDateFormat simdf = new SimpleDateFormat("yyyy-MM-dd"); Calendar calendar = new GregorianCalendar(year, 0, 1); int i = 1; while (calendar.get(Calendar.YEAR) < year + 1) { calendar.set(Calendar.WEEK_OF_YEAR, i++); calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY); if (calendar.get(Calendar.YEAR) == year) { System.out.println("周日:"+simdf.format(calendar.getTime())); dateList.add(simdf.format(calendar.getTime())); } calendar.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY); if (calendar.get(Calendar.YEAR) == year) { System.out.println("周六:"+simdf.format(calendar.getTime())); dateList.add(simdf.format(calendar.getTime())); } } System.out.println(dateList.size()); }
将 System.out.println 里的内容替换为插入数据库的代码即可
我使用了 element-UI 做了可视化界面手动修改节假日,如下图
首先我写了个方法,判断两个日期直接有几天非工作
/** * @desc 查找区间内有几天非工作日 */ public long isExistNonWorkingDayCount(List<NonOrWorkingDayDO> nonOrWorkingDayDTOList, Date startTime, Date endTime) { long count = 0; for (NonOrWorkingDayDO nonworkdo : nonOrWorkingDayDTOList) { if (isEffectiveDate(nonworkdo.getNonWorkingDate(), startTime, endTime)) { count++; } } return count; } /** * */ public static boolean isEffectiveDate(Date nowTime, Date startTime, Date endTime) { if (nowTime.getTime() == startTime.getTime() || nowTime.getTime() == endTime.getTime()) { return true; } Calendar date = Calendar.getInstance(); date.setTime(nowTime); Calendar begin = Calendar.getInstance(); begin.setTime(startTime); Calendar end = Calendar.getInstance(); end.setTime(endTime); if (date.after(begin) && date.before(end)) { return true; } else { return false; } }
判断“单子”List 距离15个工作日还剩多少天
/** * @author caeser * @date 2021-10-7 09:47:07 * @desc 只判断距离当前item创建时间15个工作日期限还剩多少天 */ List<ItemDTO> judgeOutDeadLineReminderTotalFifteenCreateTime(List<ItemDTO> itemDTOList) { List<ItemDTO> itemDTOresult = null; List<NonOrWorkingDayDO> nonOrWorkingDayDTOList = nonOrWorkingDayDAO.selectList(null); Date nowDate = new Date(); long nd = 1000 * 24 * 60 * 60; for (ItemDTO dto : itemDTOList) { // 获取当前item的创建时间 Date createTimeDate = dto.getCrterTime(); // item创建时间增加十五天 Date fifteenDeadLineDate = timeProcess(createTimeDate, 15); // 和当前日期做对比还剩多少天 // 计算当前时间差值(单位:天) long diff = fifteenDeadLineDate.getTime() - nowDate.getTime(); // 当前距离15天期限的日期有多少天 long day = diff / nd; // 判断当前时间和 到期15期限时间之间有几天非工作日 long nonworkCount = isExistNonWorkingDayCount(nonOrWorkingDayDTOList, nowDate, fifteenDeadLineDate); // 日期增加非工作日 day = day + nonworkCount; // 如果超过15天则只返回15天,不超过15天则显示正常 if (day > 15) { day = 15; } if (day < 1) { dto.setCompareNowDateAndCrterTime("1|" + day); } else { BigDecimal longToBigDel=new BigDecimal(day); dto.setDeadLineCount(longToBigDel); dto.setCompareNowDateAndCrterTime("0|" + day); } } itemDTOresult = itemDTOList; return itemDTOresult; }
我暂时没有维护春节那几天,这个工作日统计算是解决了,我在这里分享一下经验,我是这样处理的,不知道别人是怎么样解决的,我的项目不能联网,所以离线的处理办法,我只能想到这里了,至少现在是满足当前项目需求了。
有个代码需要说一下
nonOrWorkingDayDAO.selectList(null)
这一句其实就是查询所有的非工作日,并且保存到 List 里。
此次项目我们有个基本概念就是减少数据库的查询次数,越少越好。
我们还有一个需求就是查询剩余1天的单子有哪些,于是这个剩余天数,其实是需要保存起来的,我上面的代码只是每次查询都会计算一次,只是计算的数量不多,因为分页查询每次查询的数据量不多,所以我就动态计算,保证每次计算的都是最新的到期时间。
但是如果保存这个数据,就会有一个问题,第二天如何更新这个数据呢?这个时候定时任务就是必要的了,但是我在这个项目里不想加入定时任务,因为项目节假日可能会关机,这个项目完全离线,不过有个好消息是,查询剩余1天的单子有哪些是在另一个页面(姑且成为B页面),所以我在B页面的查询按钮里,加入了这样一个逻辑,我使用了单独的一张表,记录当前计算的日期,而且只记录年月日,没有具体时间,当计算过一次之后,这个日期就与当前日期相等了,只要相等则不重新计算,减少查询数据库次数,只是我新建的表只使用了一行
判断代码如下:
/// 判断日期,1、如果DATE_UPDATE日期小于当前日期则更新一次item的到期时间 if(ToolUtil.isNotEmpty(dateTargetDTOS)&&dateTargetDTOS.size()>0){ Date getNowDate=new Date(); Date dateUpdateDe=dateTargetDTOS.get(0).getDateUpdate(); DateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd"); try { getNowDate=dateFormat2.parse(dateFormat2.format(getNowDate)); dateUpdateDe=dateFormat2.parse(dateFormat2.format(dateUpdateDe)); }catch (Exception e){ throw new ExceptionManager(500,e.getMessage()); } if(getNowDate.compareTo(dateUpdateDe)<0||getNowDate.compareTo(dateUpdateDe)==0){ // 当前日期在dateUpdate之前 // System.out.println("不更新"); }else{ // 当前日期在dateBefore之后 更新到期时间 // System.out.println("更新到期时间"); } }
也就是说第二天点击查询第一次,才会更新一次数据库,第二次就不进行更新了,B页面查询的肯定是计算之后的到期时间。
以上就是我对统计工作日或者非工作日的解决方案。
工作不算多,可总是觉得挺忙的,大部分时间我们都在CRUD,普通的程序员大概如此吧。很久很久都没写博客了,要忙的事情确实不少,在公司的业务代码里,大部分内容我觉得没什么可以分享的,所以一直都没动笔写博客,希望以上内容对你有用。