根据当前时间获取几天后或下个月的日期(多退少补/工作日)及其他日期处理方法

项目中遇到的,做个记录,具体业务是:
体检号源累计增加,例如:2021-08-17哪下一个月的2021-09-17判断是否增加号源
添加的号源必须在工作日内,所以就出来了很多细节问题,例如:

  1. 如果当前日期在下个月没有怎么办?
  2. 如果当前最后一天是30号或者28号,可是下个月有30号/31号那该怎么办?
  3. 如果最后一天是31号下个月是28号/30号怎么办?
  4. 如果当前日期或者下个月多的的日期不是工作日怎么办

结合问题,所以就慢慢的实现了,就是做个笔记,有些代码细节自行修改

项目中是定时任务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);

    }
}

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值