项目中遇到的,做个记录,具体业务是:
体检号源累计增加,例如:2021-08-17哪下一个月的2021-09-17判断是否增加号源
添加的号源必须在工作日内,所以就出来了很多细节问题,例如:
- 如果当前日期在下个月没有怎么办?
- 如果当前最后一天是30号或者28号,可是下个月有30号/31号那该怎么办?
- 如果最后一天是31号下个月是28号/30号怎么办?
- 如果当前日期或者下个月多的的日期不是工作日怎么办
结合问题,所以就慢慢的实现了,就是做个笔记,有些代码细节自行修改
项目中是定时任务quartz,实现的号源自增调度(单独的总方法内部实现根据医院配置是否开启决定号源是否自增),根据医院配置的是否开启任务进行各个医院的号源自增
public List<String> getAddDateList() throws ParseException {
List<String> addList = new ArrayList<>();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 获取当前时间
Calendar calendar = Calendar.getInstance();
//TODO: 本地测试用例
//Date parse = sdf.parse("2021-03-31");
//System.err.println("dateString: "+dateString);
//Date parse = sdf.parse(dateString);
//calendar.setTime(parse);
//获取当前月的天数
int nowDays = calendar.getActualMaximum(Calendar.DATE);
//获取当前的日期是第几天
int dateDay = calendar.get(Calendar.DATE);
//当前月加1
calendar.add(Calendar.MONTH, 1);
//获取下个月的今天是星期几
int week = calendar.get(Calendar.DAY_OF_WEEK) - 1;
//获取下个月的最大天数
int lastDays = calendar.getActualMaximum(Calendar.DATE);
//计算多出的天数或少出的天数
int dys = nowDays - lastDays;
if(dys > 0){
//当前月比下个月天数多
if((nowDays -dateDay) < dys){
//说明当前天数在下个月存不在,则不进行添加操作
return addList;
}
//如果当天在下个月存在
if(week > 0 && week < 6){
//将下个月日期添加到要增加的list中
addList.add(sdf.format(calendar.getTime()));
}
}else{
//如果不是最后一天则单独添加
if(week > 0 && week < 6){
//将下个月日期添加到要增加的list中
addList.add(sdf.format(calendar.getTime()));
}
//说明当前月比下个月少,最后几天循环添加
if(nowDays == dateDay){
//将剩余的没有的天数补添
for (int i = 1; i <= (-dys); i++) {
calendar.add(Calendar.DATE ,1);
int weekFor = calendar.get(Calendar.DAY_OF_WEEK) - 1;
if(weekFor > 0 && weekFor < 6){
//是工作日进行补加,将下个月日期添加到要增加的list中
addList.add(sdf.format(calendar.getTime()));
}
}
return addList;
}
}
return addList;
}
项目中使用的日期工具类
package com.example.juc;
import com.sun.istack.internal.NotNull;
import lombok.extern.slf4j.Slf4j;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* 定时任务
* @author qubing
* @date 2021/10/11 15:57
*/
@Slf4j
public class TaskUtils {
/**
* 日期格式
*/
private static final String DATE_FORMAT = "MM-dd";
/**
* 中国法定节假日期
* 2021:01-01,01-02,01-03,01-31,02-01,02-02,02-03,02-04,02-05,02-06,04-03,04-04,04-05,05-01,05-02,
* * 05-03,05-04,06-03,06-04,06-05,09-10,09-11,09-12,10-01,10-02,10-03,10-04,10-05,10-06,10-07
*/
private static final String IS_HOLIDAY = "01-01,01-02,01-03,01-31,02-01,02-02,02-03,02-04,02-05,02-06,04-03,04-04,04-05,05-01,05-02, "
+ "05-03,05-04,06-03,06-04,06-05,09-10,09-11,09-12,10-01,10-02,10-03,10-04,10-05,10-06,10-07";
/**
* 节假前后加班日期
* 2021: "01-05,01-06,02-16,02-17,04-07,04-17,04-28,06-08,06-09,09-18,09-26,10-09"
*/
private static final String OVER_DAY = "01-29,01-30,04-02,04-24,05-07,10-08,10-09";
private static final String HOS_URL_KEY = "hosUrl";
private static final String SECRET_KEY = "secretKey";
/**
* 指定日期是否是休息日 false:不是休息日 true:是休息日
* @param dateStr 日期字符串 yyyy-MM-dd
* @return Boolean
*/
public static boolean hasRest(@NotNull String dateStr) {
try {
log.info("[hasRest start] --> dateStr:{}", dateStr);
Calendar calendar = Calendar.getInstance();
SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd");
Date parse = sdfDate.parse(dateStr);
calendar.setTime(parse);
//获取下个月的今天是星期几
int week = calendar.get(Calendar.DAY_OF_WEEK) - 1;
log.info("[hasRest ] --> 周几,数字 week:{}", week);
SimpleDateFormat sdfDateTo = new SimpleDateFormat(DATE_FORMAT);
String format1 = sdfDateTo.format(calendar.getTime());
log.info("[hasRest ] --> 日期 format1:{}", format1);
if (week > 0 && week < 6 && !IS_HOLIDAY.contains(format1)) {
return false;
}
//判断当前日期是否是加班日期
return !OVER_DAY.contains(format1);
} catch (ParseException e) {
e.printStackTrace();
log.info("[hasRest ] --> 日期判断异常:{}", e.getMessage());
return false;
} finally {
log.info("[hasRest end] --> dateStr:{}", dateStr);
}
}
/**
* 获取号源调度的日期list
* @param days 天数
* @param hasJumpRest 是否跳过休息日
* @param hasDayNow 是否生成当天
* @return List<String> 是否跳过休息日
*/
public static List<String> getAddDateList(Integer days, boolean hasJumpRest,
boolean hasDayNow) {
List<String> addList = new ArrayList<>();
// 获取当前时间
Calendar calendar = Calendar.getInstance();
//获取当前月的天数
int nowDays = calendar.getActualMaximum(Calendar.DATE);
//获取当前的日期是第几天
log.info("是否生成当天排班:{}", hasDayNow);
int dateDay = calendar.get(Calendar.DATE);
if (!hasDayNow) {
if (days == 0) {
//当前月加1
calendar.add(Calendar.MONTH, 1);
} else {
//当前月加1
calendar.add(Calendar.DATE, days);
}
}
//获取下个月的当前日期判断是否是加班或者节日用
SimpleDateFormat sdfDate = new SimpleDateFormat(DATE_FORMAT);
String format1 = sdfDate.format(calendar.getTime());
//获取下个月的今天是星期几
int week = calendar.get(Calendar.DAY_OF_WEEK) - 1;
//获取下个月的最大天数
int lastDays = calendar.getActualMaximum(Calendar.DATE);
//计算多出的天数或少出的天数
int dys = nowDays - lastDays;
if (dys > 0) {
//当前月比下个月天数多 注意:当前如果是按月加则需要判断下个月是否有今天
if ((nowDays - dateDay) < dys && days == 0) {
//说明当前天数在下个月存不在,则不进行添加操作
return addList;
}
setDateListCheck(week, calendar, format1, addList, hasJumpRest);
} else {
//如果不是最后一天则单独添加
setDateListCheck(week, calendar, format1, addList, hasJumpRest);
//说明当前月比下个月少,最后几天循环添加 注意:当前如果是按照月增加,如果是当月最后一个月则需要循环循环创建下个月多出的日期
if (nowDays == dateDay && days == 0) {
//将剩余的没有的天数补添
for (int i = 1; i <= (-dys); i++) {
calendar.add(Calendar.DATE, 1);
int weekFor = calendar.get(Calendar.DAY_OF_WEEK) - 1;
setDateListCheck(weekFor, calendar, sdfDate.format(calendar.getTime()), addList,
hasJumpRest);
}
return addList;
}
}
return addList;
}
/**
* 获取今天 workingDay 个工作日之后的日期
* @param calendar 当前时间的日历对象 [ 如果日历为null,默认获取当前日期 ]
* @param workingDay 获取到少个工作日之后的排班 [ 默认 3 天之后 ]
* @return String 最终的日期
*/
public static String getStartDate(ThreadLocal<SimpleDateFormat> simpleDateFormat,
Calendar calendar, Integer workingDay) throws ParseException {
if (simpleDateFormat == null) {
simpleDateFormat = new ThreadLocal<>();
simpleDateFormat.set(new SimpleDateFormat("yyyy-MM-dd"));
}
if (calendar == null) {
String newDate = simpleDateFormat.get().format(new Date());
Date parse1 = simpleDateFormat.get().parse(newDate);
calendar = Calendar.getInstance();
calendar.setTime(parse1);
}
workingDay = workingDay == null ? 3 : workingDay;
SimpleDateFormat sdfDate = new SimpleDateFormat(DATE_FORMAT);
String nowDate;
int week;
boolean b = true;
// 循环处理日期
while (b) {
calendar.add(Calendar.DATE, 1);
nowDate = sdfDate.format(calendar.getTime());
week = calendar.get(Calendar.DAY_OF_WEEK) - 1;
boolean hasWorkingDay = IS_HOLIDAY.contains(nowDate) || week == 0 || week == 6;
//条件一 当前不是假期 /条件二:当前是国定加班日
if (!hasWorkingDay || OVER_DAY.contains(nowDate)) {
workingDay--;
}
b = hasWorkingDay || workingDay > 0;
}
String format = simpleDateFormat.get().format(calendar.getTime());
simpleDateFormat.remove();
return format;
}
/**
* dateList 处理
* @param week 数字--星期几数字排列和名字是有区别的 6->星期6, 0->星期日
* @param calendar 当前日期日历实体
* @param format1 当前日期字符串
* @param addList 排班日期结果集
* @param hasJustRest 是否跳过休息日
*/
public static void setDateListCheck(int week, Calendar calendar, String format1,
List<String> addList, boolean hasJustRest) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//如果当天在下个月存在,判断星期几,并且不是法定节假日才进行新增
if (hasJustRest) {
if (week > 0 && week < 6 && !IS_HOLIDAY.contains(format1)) {
//将下个月日期添加到要增加的list中
addList.add(sdf.format(calendar.getTime()));
} else if (OVER_DAY.contains(format1)) {
//判断当前日期是否是加班日期
log.info("格式化日期: {}", format1);
addList.add(sdf.format(calendar.getTime()));
log.info("加班日期进行排班");
}
} else {
//[ 说明不跳过休息日,则直接增加日期到集合 ]
addList.add(sdf.format(calendar.getTime()));
}
}
public static void main(String[] args) {
List<String> addDateList = getAddDateList(3, false, false);
System.err.println(addDateList);
}
}