欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

工作日节假日调休日休息日的判断API-holiday

程序员文章站 2022-02-19 06:34:06
...

工作日节假日调休日休息日的判断API-holiday

1. 背景

从2019年开始接一个需求,调单设置超期反馈时间T+2及邮件发送时间T+1都需要排除休息日;之前一个接口http://api.goseek.cn/ 是可以获取到全年每一天的性质四种<后续介绍>;但是2020年需要更新数据了,这个页面就打不开了,开始想法自己实现,并想做成静态工具类。

2. 设计思路

若没有节假日,则只分为工作日和周末;国务院每年11或12月份公布下一年的节假日及调休日;由于这些日子比较少且是固定的,因此只需要将这些保存下来,通过代码逻辑就可以判断出一年中每一天的性质。

性质分成四种:

 # 某一天的性质分成四种:
 # 0. 正常工作日为0,Weekday
 # 1. 正常周六日为1,Weekend
 # 2. 法定节假日为2,holiday
 # 3. 周六日调休补班为3,makeUp4Rest

*网: http://www.gov.cn/zhengce/content/2019-11/21/content_5454164.htm

经国务院批准,现将2020年元旦、春节、清明节、劳动节、端午节、国庆节和中秋节放假调休日期的具体安排通知如下。

一、元旦:2020年1月1日放假,共1天。

二、春节:1月24日至30日放假调休,共7天。1月19日(星期日)、2月1日(星期六)上班。

三、清明节:4月4日至6日放假调休,共3天。

四、劳动节:5月1日至5日放假调休,共5天。4月26日(星期日)、5月9日(星期六)上班。

五、端午节:6月25日至27日放假调休,共3天。6月28日(星期日)上班。

六、国庆节、中秋节:10月1日至8日放假调休,共8天。9月27日(星期日)、10月10日(星期六)上班。

 ##实现方式:
 # 正常情况下,根据周六日即可获取正常工作日和周六日;
 # 由于法定节假日及调休补班的日子比较少,将两种手动保存下来,作为排除即可。
 ​
 # 2020年法定节假日
 holiday_2020=0101,0124,0125,0126,0127,0128,0129,0130,0125,0125,0125,0125,0125,0125,0404,0405,0406,0501,0502,0503,0504,0505,0625,0627,1001,1002,1003,1004,1005,1006,1007,1008
 # 2020年调休补班
 makeUp4Rest_2020=0119,0201,0426,0509,0628,0927,1010
 ​
 # 2021年法定节假日
 #holiday_2021=
 # 2021年调休补班
 #makeUp4Rest_2021=

我采用的是将这些日期存放在配置文件中holiday.properties中,key后缀为年份,代码中动态去加载。

为了做成静态工具类WorkingDay,这里通过静态代码块将properties文件中的配置信息解析成两个Set集合:

 
//节假日
 private static Set<String> holidaySet;
 //调休补班
 private static Set<String> makeUp4RestSet;
     static {
         try {
             ClassPathResource cpr = new ClassPathResource("holiday.properties");
             Properties properties = new Properties();
             properties.load(cpr.getInputStream());
             int year = new DateTime().getYear();
             String holidayStr = (String) properties.get("holiday_" + year);
             holidaySet = new HashSet<>(Arrays.asList(
                 StringUtils.split(holidayStr, ',')));
             String makeUp4RestStr = (String) properties.get("makeUp4Rest_" + year);
             makeUp4RestSet = 
                 new HashSet<>(Arrays.asList(StringUtils.split(makeUp4RestStr, ',')));
             logger.info("加载节假日配置文件得到holidaySet={},
                         makeUp4RestSet={}", holidaySet, makeUp4RestSet);
         } catch (IOException e) {
             logger.error("加载节假日配置文件holiday.properties出现异常:", e);
         }
     }
 WorkingDay工具类的API:
     //是否工作日
     public static boolean isWorkingDay(Date date){}
     //判断date的性质返回Enum或code
     public DateTypeEnum judgeDateTypeEnum(Date date) {}
     public Integer judgeDateTypeCode(Date date) {}
     //获取与date相隔一定工作日的日期(days<0向前,days>0向后)
     public static Date plusWorkingDay(Date date, Integer days){}

3. 总结

配置信息也可以存放在数据库中,当然也可以直接定义在代码中。当然更改数据库是最灵活的,不需要更新代码和重启服务器。

每年国务院发布一次节假日及调休信息后,只需要添加配置就可以了,后缀是需要配置的年份。

附件:

1. WorkingDay.java

 
import com.jd.common.util.StringUtils;
 import org.joda.time.DateTime;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.core.io.ClassPathResource;
 ​
 import java.io.IOException;
 import java.text.SimpleDateFormat;
 import java.util.*;
 ​
 /**
  * 工作日实现类
  *
  * @Author zhaohong
  * @Date 2020/4/14 18:18
  */
 public class WorkingDay {
     private static Logger logger = LoggerFactory.getLogger(WorkingDay.class);
 ​
     //节假日
     private static Set<String> holidaySet;
     //调休补班
     private static Set<String> makeUp4RestSet;
 ​
     static {
         try {
             ClassPathResource cpr = new ClassPathResource("holiday.properties");
             Properties properties = new Properties();
             properties.load(cpr.getInputStream());
             int year = new DateTime().getYear();
             String holidayStr = (String) properties.get("holiday_" + year);
             holidaySet = new HashSet<>(Arrays.asList(StringUtils.split(holidayStr, ',')));
             String makeUp4RestStr = (String) properties.get("makeUp4Rest_" + year);
             makeUp4RestSet = new HashSet<>(Arrays.asList(StringUtils.split(makeUp4RestStr, ',')));
             logger.info("加载节假日配置文件得到holidaySet={},makeUp4RestSet={}", holidaySet, makeUp4RestSet);
         } catch (IOException e) {
             logger.error("加载节假日配置文件holiday.properties出现异常:", e);
         }
     }
 ​
     /**
      * 获取与date相隔days个工作日
      *
      * @param date null默认为当前时间
      * @param days null返回date
      * @return
      */
     public static Date plusWorkingDay(Date date, Integer days) {
         if (date == null) {
             date = new Date();
         }
         if (days == null || days.intValue() == 0) {
             //days == 0时返回date
             return date;
         }
         int daysAbs = Math.abs(days);
         //days> 0,1;days<0,-1
         int plusNum = days / daysAbs;
         DateTime dateTime = new DateTime(date);
         while (daysAbs > 0) {
             dateTime = dateTime.plusDays(plusNum);
             if (isWorkingDay(dateTime.toDate())) {
                 daysAbs--;
             }
         }
         return dateTime.toDate();
     }
 ​
     /**
      * 是否是工作日(需要工作的日子):包括调休补班
      * # 某一天的性质分成四种:
      * # 0. 正常工作日为0,Weekday
      * # 1. 正常周六日为1,Weekend
      * # 2. 法定节假日为2,holiday
      * # 3. 周六日调休补班为3,makeUp4Rest
      *
      * @param date
      * @return
      */
     public static boolean isWorkingDay(Date date) {
         SimpleDateFormat sdf = new SimpleDateFormat("MMdd");
         String monDay = sdf.format(date);
         //是否是节假日
         if (holidaySet.contains(monDay)) {
             return false;
         }
         //非节假日
         Calendar calendar = Calendar.getInstance();
         calendar.setTime(date);
         //周日1---周六7
         int week = calendar.get(Calendar.DAY_OF_WEEK);
         //排除节假日之外的工作日必须工作;需要调休补班的周六日需要工作
         if ((week > 1 && week < 7) || makeUp4RestSet.contains(monDay)) {
             return true;
         }
         return false;
     }
 ​
     /**
      * 取date的性质返回code 0/1/2/3
      *
      * @param date
      * @return
      */
     public Integer judgeDateTypeCode(Date date) {
         DateTypeEnum dateTypeEnum = judgeDateTypeEnum(date);
         return dateTypeEnum != null ? dateTypeEnum.getCode() : null;
     }
 ​
     /**
      * 获取date的性质返回枚举类型
      *
      * @param date
      * @return
      */
     public DateTypeEnum judgeDateTypeEnum(Date date) {
         SimpleDateFormat sdf = new SimpleDateFormat("MMdd");
         String monDay = sdf.format(date);
         //是否是节假日
         if (holidaySet.contains(monDay)) {
             return DateTypeEnum.HOLIDAY;
         }
         //调休补班日
         if (makeUp4RestSet.contains(monDay)) {
             return DateTypeEnum.MAKE_UP_4_REST;
         }
         //
         //非节假日
         Calendar calendar = Calendar.getInstance();
         calendar.setTime(date);
         //周日1---周六7
         int week = calendar.get(Calendar.DAY_OF_WEEK);
         if (week > 1 && week < 7) {
             return DateTypeEnum.NORMAL_WEEKDAY;
         }
         return DateTypeEnum.NORMAL_WEEKEND;
     }
 ​
     /**
      * 某一天的性质分成四种:
      * 0. 正常工作日为0,Weekday
      * 1. 正常周六日为1,Weekend
      * 2. 法定节假日为2,holiday
      * 3. 周六日调休补班为3,makeUp4Rest
      */
     public enum DateTypeEnum {
         NORMAL_WEEKDAY(0, "正常工作日"),
         NORMAL_WEEKEND(1, "正常周六日"),
         HOLIDAY(2, "节假日"),
         MAKE_UP_4_REST(3, "调休补班日");//原是周六日才会需要补班
 ​
         DateTypeEnum(int code, String desc) {
             this.code = code;
             this.desc = desc;
         }
 ​
         private int code;
         private String desc;
 ​
         public int getCode() {
             return code;
         }
 ​
         public String getDesc() {
             return desc;
         }
     }
 }

2. holiday.properties文件

 # 2020年法定节假日
 holiday_2020=0101,0124,0125,0126,0127,0128,0129,0130,0125,0125,0125,0125,0125,0125,0404,0405,0406,0501,0502,0503,0504,0505,0625,0627,1001,1002,1003,1004,1005,1006,1007,1008
 # 2020年调休补班
 makeUp4Rest_2020=0119,0201,0426,0509,0628,0927,1010
 ​
 # 2021年法定节假日
 #holiday_2021=
 # 2021年调休补班
 #makeUp4Rest_2021=