场景

我们在一些特殊的业务场景下,想要获取到下一个工作日,这里的工作日指正常的法定工作日(包含调休日),这个需求来源于银联的提现,银联只能在法定工作日才能体现,那么在业务代码里对提现日期必须就是工作日即可,在查询了相关的信息,目前没有稳定的API或者三方付费的稳定API,那么这个需求其实不难处理,自己也可以动手维护一套WorkingHolidayAPI的,那么我就以Springboot简答举例写出重要的环节。


文章目录

  • 场景
  • 代码
  • Springboot单元测试
  • 原理
    • 优化项
  • 总结

代码

关键工具:


import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.Week;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;public class WorkingHolidayUtil {private static final int DEFAULT_YEAR_DAY = 365;private Map<Integer, WorkingHoliday> whMap;/*** 创建时间*/private Date createTime;/*** 起始日期*/private Date startDay;/****/private int offDay;/*** 权重比例**/private int[] WEIGHT_ARR = {10000, 100, 1};public WorkingHolidayUtil(List<WorkingHolidayEntity> data, Date startDay, int offDay) {if (data.isEmpty()) {throw new RuntimeException("构建参数源不能为空");}if (startDay == null) {throw new RuntimeException("构建参数源起始日期不能为空");}if (offDay <= 0) {throw new RuntimeException("构建参数偏移天数只能为正整数");}this.createTime = new Date();this.startDay = startDay;this.offDay = offDay > DEFAULT_YEAR_DAY * 10 ? DEFAULT_YEAR_DAY * 10 : offDay;this.whMap = new ConcurrentHashMap<>(offDay);buildBaseNode(data);}public WorkingHolidayUtil(List<WorkingHolidayEntity> data, Date startDay) {if (data.isEmpty()) {throw new RuntimeException("构建参数源不能为空");}if (startDay == null) {throw new RuntimeException("构建参数源起始日期不能为空");}this.createTime = new Date();this.startDay = startDay;this.offDay = DEFAULT_YEAR_DAY;this.whMap = new ConcurrentHashMap<>(offDay);buildBaseNode(data);}private boolean buildBaseNode(List<WorkingHolidayEntity> data) {Map<String, WorkingHolidayEntity> dataMap = new HashMap<>(1 << 10);if (!data.isEmpty()) {for (WorkingHolidayEntity whe : data) {dataMap.put(whe.getDayStr(), whe);}}return doBuildBaseNode(dataMap);}private boolean doBuildBaseNode(Map<String, WorkingHolidayEntity> dataMap) {Date curDate = DateUtil.date(startDay);String date = "unknow";int weight = -1;String source = "unknow";int holidayOrWorkingday = -1;WorkingHoliday lastWorkingDay = null;List<WorkingHoliday> lastWorkingDays = new ArrayList<>(DEFAULT_YEAR_DAY);WorkingHoliday lastHolidayDay = null;List<WorkingHoliday> lastHolidayDays = new ArrayList<>(DEFAULT_YEAR_DAY);String remark = "";for (int i = 0; i < offDay; i++) {date = DateUtil.format(curDate, "yyyy-MM-dd");weight = getWeight(curDate);if (!dataMap.isEmpty() && dataMap.containsKey(date)) {WorkingHolidayEntity dbItem = dataMap.get(date);source = "db";holidayOrWorkingday = dbItem.getHolidayOrWorkingday();remark = dbItem.getRemark();} else {Week week = DateUtil.dayOfWeekEnum(curDate);int dayOfWeek = week.getValue();source = "hutool";if (dayOfWeek == 1 || dayOfWeek == 7) {holidayOrWorkingday = 2;} else {holidayOrWorkingday = 3;}remark = week.toChinese();}WorkingHoliday wh = new WorkingHoliday(weight, date, holidayOrWorkingday, source, remark);// 偶休息 奇工作if (holidayOrWorkingday % 2 == 0) {clearArrs(0, lastWorkingDays, weight);if (lastHolidayDay != null) {lastHolidayDay.setNextHolidayDayWeight(weight);}lastHolidayDay = wh;lastHolidayDays.add(lastHolidayDay);} else {clearArrs(1, lastHolidayDays, weight);if (lastWorkingDay != null) {lastWorkingDay.setNextWorkingDayWeight(weight);}lastWorkingDay = wh;lastWorkingDays.add(lastWorkingDay);}whMap.put(weight, wh);curDate = DateUtil.offsetDay(curDate, 1);}return !whMap.isEmpty();}/*** @param holidayOrWorkingday* @param workingHolidays* @param weight*/private void clearArrs(int holidayOrWorkingday, List<WorkingHoliday> workingHolidays, int weight) {if (holidayOrWorkingday == 0) {for (WorkingHoliday e : workingHolidays) {e.setNextHolidayDayWeight(weight);}} else {for (WorkingHoliday e : workingHolidays) {e.setNextWorkingDayWeight(weight);}}workingHolidays.clear();}private int getWeight(Date curDate) {int year = DateUtil.year(curDate);int month = DateUtil.month(curDate) + 1;int day = DateUtil.dayOfMonth(curDate);return WEIGHT_ARR[0] * year + WEIGHT_ARR[1] * month + WEIGHT_ARR[2] * day;}private int getWeight(String curDate) {return getWeight(DateUtil.parse(curDate, "yyyy-MM-dd"));}public WorkingHoliday nextWorkingDay(String curDate) {int weight = getWeight(curDate);if (!whMap.containsKey(weight)) {throw new RuntimeException("数据源不存在当前日期");}WorkingHoliday workingHoliday = whMap.get(weight);while (true) {if (workingHoliday == null) {throw new RuntimeException("目前找不到下一个工作日");}Integer nextWorkingDayWeight = workingHoliday.getNextWorkingDayWeight();if (nextWorkingDayWeight != null) {return whMap.get(nextWorkingDayWeight);} else {String date = workingHoliday.getDate();DateTime dateTime = DateUtil.offsetDay(DateUtil.parse(date, "yyyy-MM-dd"), 1);int nextDayWeight = getWeight(dateTime);workingHoliday = whMap.containsKey(nextDayWeight) ? whMap.get(nextDayWeight) : null;}}}}

模型:

public class WorkingHoliday {/*** 权重*/private int weight;/*** 日期* yyyy-MM-dd*/private String date;/*** 法定工作日/休息日* 0法定休息日* 1法定工作日* 2正常休息日* 3正常工作日* <p>* 偶数休息 奇数工作*/private int holidayOrWorkingday;/*** 来源* db数据库 hutool糊涂*/private String source;/*** 下一个工作日权重*/private Integer nextWorkingDayWeight;/*** 下一个休息日权重*/private Integer nextHolidayDayWeight;private String remark;public WorkingHoliday() {}public WorkingHoliday(int weight, String date, int holidayOrWorkingday, String source, String remark) {this.weight = weight;this.date = date;this.holidayOrWorkingday = holidayOrWorkingday;this.source = source;this.remark = remark;}public Integer getNextWorkingDayWeight() {return nextWorkingDayWeight;}public void setNextWorkingDayWeight(Integer nextWorkingDayWeight) {this.nextWorkingDayWeight = nextWorkingDayWeight;}public Integer getNextHolidayDayWeight() {return nextHolidayDayWeight;}public void setNextHolidayDayWeight(Integer nextHolidayDayWeight) {this.nextHolidayDayWeight = nextHolidayDayWeight;}public int getWeight() {return weight;}public void setWeight(int weight) {this.weight = weight;}public String getDate() {return date;}public void setDate(String date) {this.date = date;}public int getHolidayOrWorkingday() {return holidayOrWorkingday;}public void setHolidayOrWorkingday(int holidayOrWorkingday) {this.holidayOrWorkingday = holidayOrWorkingday;}public String getSource() {return source;}public void setSource(String source) {this.source = source;}public String getRemark() {return remark;}public void setRemark(String remark) {this.remark = remark;}@Overridepublic String toString() {return "WorkingHoliday{" +"weight=" + weight +", date='" + date + '\'' +", holidayOrWorkingday=" + holidayOrWorkingday +", source='" + source + '\'' +", nextWorkingDayWeight=" + nextWorkingDayWeight +", nextHolidayDayWeight=" + nextHolidayDayWeight +", remark='" + remark + '\'' +'}';}
}

实体类

package com..finance.common.entity;import java.io.Serializable;
import java.util.Date;public class WorkingHolidayEntity  implements Serializable {/*** 日期*/private Date dayStr;/*** 法定工作日/休息日* 0法定休息日* 1法定工作日* 2正常休息日* 3正常工作日** 偶数休息 奇数工作*/private int holidayOrWorkingday;/*** 备注*/private String remark;public Date getDayStr() {return dayStr;}public void setDayStr(Date dayStr) {this.dayStr = dayStr;}public int getHolidayOrWorkingday() {return holidayOrWorkingday;}public void setHolidayOrWorkingday(int holidayOrWorkingday) {this.holidayOrWorkingday = holidayOrWorkingday;}public String getRemark() {return remark;}public void setRemark(String remark) {this.remark = remark;}@Overridepublic String toString() {return "WorkingHolidayEntity{" +"dayStr='" + dayStr + '\'' +", holidayOrWorkingday=" + holidayOrWorkingday +", remark='" + remark + '\'' +'}';}
}

业务实现类

@Service
public class WorkingHolidayServiceImpl implements IWorkingHolidayService {private WorkingHolidayUtil workingHolidayUtil;private String glCurDate;@Autowiredprivate WorkingHolidayDao workingHolidayDao;@Overridepublic WorkingHoliday nextWorkingDay(String curDate) {if (!curDate.equals(glCurDate) || workingHolidayUtil == null) {synchronized (this) {if (!curDate.equals(glCurDate) || workingHolidayUtil == null) {DateTime dateTime = DateUtil.parse(curDate, "yyyy-MM-dd");List<WorkingHolidayEntity> datas = workingHolidayDao.egYearWorkingHolidays(String.valueOf(dateTime.year()));workingHolidayUtil = new WorkingHolidayUtil(datas, dateTime);glCurDate = curDate;}}}return workingHolidayUtil.nextWorkingDay(curDate);}}

Dao关键SQL语句

<select id="egYearWorkingHolidays" parameterClass="java.lang.String"resultClass="com..finance.common.entity.WorkingHolidayEntity">SELECTDAY_STR dayStr,HOLIDAY_OR_WORKINGDAY  holidayOrWorkingday,REMARK remarkFROM"WORKING_HOLIDAY"WHERESUBSTR( DAY_STR, 0, 4 ) <![CDATA[>= ]]> #year#ORDER BYDAY_STR ASC</select>

DDL表构建(oracle)

CREATE TABLE "WORKING_HOLIDAY" (   "DAY_STR" VARCHAR2(10) NOT NULL ENABLE, "HOLIDAY_OR_WORKINGDAY" CHAR(1) NOT NULL ENABLE, "REMARK" VARCHAR2(500))

表数据填充

INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-01-01', '0', '元旦');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-01-02', '0', '元旦');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-01-03', '0', '元旦');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-01-29', '1', '春节调休');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-01-30', '1', '春节调休');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-01-31', '0', '春节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-02-01', '0', '春节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-02-02', '0', '春节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-02-03', '0', '春节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-02-04', '0', '春节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-02-05', '0', '春节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-02-06', '0', '春节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-04-02', '1', '清明节调休');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-04-03', '0', '清明节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-04-04', '0', '清明节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-04-05', '0', '清明节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-04-24', '1', '劳动节调休');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-04-30', '0', '劳动节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-05-01', '0', '劳动节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-05-02', '0', '劳动节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-05-03', '0', '劳动节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-05-04', '0', '劳动节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-05-07', '1', '劳动节调休');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-06-03', '0', '端午节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-06-04', '0', '端午节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-06-05', '0', '端午节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-09-10', '0', '中秋节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-09-11', '0', '中秋节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-09-12', '0', '中秋节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-10-01', '0', '国庆节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-10-02', '0', '国庆节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-10-03', '0', '国庆节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-10-04', '0', '国庆节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-10-05', '0', '国庆节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-10-06', '0', '国庆节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-10-07', '0', '国庆节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-10-08', '1', '国庆节调休');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2022-10-09', '1', '国庆节调休');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-09-21', '0', '中秋节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-09-18', '1', '中秋节调休');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-10-01', '0', '国庆节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-10-02', '0', '国庆节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-10-03', '0', '国庆节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-10-04', '0', '国庆节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-10-05', '0', '国庆节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-10-06', '0', '国庆节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-10-07', '0', '国庆节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-10-09', '1', '国庆节调休');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-09-26', '1', '国庆节调休');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-01-01', '0', '元旦');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-01-02', '0', '元旦');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-01-03', '0', '元旦');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-02-11', '0', '春节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-02-12', '0', '春节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-02-13', '0', '春节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-02-14', '0', '春节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-02-15', '0', '春节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-02-16', '0', '春节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-02-17', '0', '春节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-02-07', '1', '春节调休');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-02-20', '1', '春节调休');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-04-03', '0', '清明节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-04-04', '0', '清明节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-04-05', '0', '清明节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-05-01', '0', '劳动节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-05-02', '0', '劳动节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-05-03', '0', '劳动节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-05-04', '0', '劳动节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-05-05', '0', '劳动节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-04-25', '1', '劳动节调休');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-05-08', '1', '劳动节调休');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-06-12', '0', '端午节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-06-13', '0', '端午节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-06-14', '0', '端午节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-09-19', '0', '中秋节');
INSERT INTO "WORKING_HOLIDAY" VALUES ('2021-09-20', '0', '中秋节');

Springboot单元测试

调用IWorkingHolidayService.nextWorkingDay(curDate) 即可

原理

实现过程也很简单,因为法定节假日法定工作日长时间是稳定不变,在此基础上,我们先通过以数据表为基础,再以hutool为辅助,来完成近365天的所有法定日的标记,通过维护好的线程安全map我们很快就能获取到具体某一日的下一个工作日是哪一天。

优化项

  1. 可以将实时获取到数据库数据的操作改为每天一获取最新的
  2. 根据大部分业务来说固定offDay的长度,并注入到容器中
  3. 完善其方法,比如下一个休息日等需要的方法

总结

很简单的实现不是么,没有花里胡哨的操作,一起加油

获取下一个工作日/休息日的方法 本地基础搭建 Springboot 法定节假日/休息日/调休日 均可 不用调三方相关推荐

  1. python获取工作日_python – 获取下一个工作日的日期

    我正在检查当前日期是否是工作日,如果不是,我想获得下一个工作日.工作日是周一至周五. 这是我尝试过的: import time from datetime import date,timedelta ...

  2. c语言fgetc()函数(从指定的流 stream 获取下一个字符(一个无符号字符),并把位置标识符往前移动)

    C 标准库 - <stdio.h> 文章目录 描述 声明 参数 返回值 实例 描述 C 库函数 int fgetc(FILE *stream) 从指定的流 stream 获取下一个字符(一 ...

  3. activiti根据当前节点获取下一个UseTask节点

    以前写过一篇文章activiti根据当前节点获取下一个节点信息,当时的需求只是需要获取下一个节点而已,并没有要求获得什么类型的节点,所以下一个节点可能是任何节点,在最近的项目中的需求是根据当前的节点获 ...

  4. activiti根据当前节点获取下一个节点信息

    在流程中使用监听器判断当前节点是否需要经过,否则跳转到下一个节点,如下图 当提交申请之后,当前提交人为部门负责人,那么部门负责人节点就不需要走了,直接到下一个节点,但是下一个节点是什么并不知道,就可以 ...

  5. 获取下一个周几的日期

    获取下一个周几的日期 直接上代码: Integer day = null; //初始化,值为1~7,分别代表周一~周日 LocalDate weekDate = LocalDate.now().wit ...

  6. python 利用chinese_calendar 获取上一个工作日日期

    **截止文章发布chinese_calendar版本为1.8.0,大约在每年的11月份更新次年的节假日新版本 import datetime from chinese_calendar import ...

  7. spring boo_为您的下一个基于Spring的应用程序考虑使用spring-boot的原因!

    spring boo Spring-boot提供了一种创建基于Spring的应用程序的快速方法. 对于下一个项目,有一些非常令人信服的理由考虑使用Spring-boot: 原因1:使用spring-b ...

  8. 为您的下一个基于Spring的应用程序考虑使用spring-boot的原因!

    Spring-boot提供了一种创建基于Spring的应用程序的快速方法. 对于下一个项目,有一些非常令人信服的理由考虑使用Spring-boot: 原因1:使用spring-boot启动程序项目进行 ...

  9. html 获取下一个兄弟节点,JS/JQuery获取当前元素的上一个/下一个兄弟级元素等元素的方法...

    $(function(){ //遍历获取的input元素对象数组,绑定click事件 var len = $("input[type='file']").length; for(v ...

最新文章

  1. flask 使用 SQLAlchemy 的两种方式
  2. linuxpython重定向_linux命令重定向、、 1、 2、 1、 2、
  3. 18.self关键字.rs
  4. 学python对数学要求高吗_人工智能的小男孩 大专学历的人没有数学基础想学习python技术未来能往大数据或人工智能方向进行职业发展吗?...
  5. SpringCloudBus(了解)
  6. 以太网供电新标准POE+,IEEE802.3at解析
  7. C/C++的思索 C++之父访谈录
  8. SpringBoot - yml与properties配置文件及bean赋值
  9. 【Flink】Flink CancellationException null DefaultExecutionGraphCache LeaderRetrievalHandler
  10. 上海电力学院计算机软件技术大作业,计算机网络应用设计 大作业报告.doc
  11. AirServer for mac如何实现无线投屏
  12. PreferenceScreen1
  13. Vue + Spring Boot 项目实战(十一):用户角色权限管理模块设计
  14. 小数点化分数的过程_怎么把小数化成分数
  15. 实验室预约管理系统 实验设备 笔记本
  16. 计算机前沿知识论文,计算机前沿技术论文.pdf
  17. 武汉服务器维修哪里专业报价,入门服务器 武汉IBM X3100报价5500元
  18. 推荐引擎的基本入门知识
  19. 修复好一个科脉软件数据库
  20. 微信支付接口升级(微信开通免充值产品功能的前戏)

热门文章

  1. 运动与数据的碰撞,华为分析运动健康行业模板上线
  2. 深圳三职计算机系,深圳市第三职业技术学校教师周贵航 职业技能人才将迎来黄金发展期...
  3. DOS常用命令及进制转换
  4. 非负矩阵图像融合MATLAB,图像融合的非负矩阵分解算法
  5. 交换机启用光口命令_交换机常用命令
  6. 新华三交换机console口如何设置密码
  7. 7脚5位数码管驱动程序
  8. oracle的sga和pga大小设置
  9. antd表格列自定义显示与隐藏
  10. USART RX 不上拉的后果