某日是否为工作日

前言

工作日就是我们常说的星期一到星期五,休息日就是星期六星期天;而法定节假日的存在打破了这种规律,会出现星期六是法定加班日,而星期一成了节假日。国家每年年底会公布第二年的节假日,由于是描述性文字的方式公布的,所以这些数据还需要通过人工处理,才可以使用。如果想省去每年人工的处理,我们可以直接使用百度的日历API来获取节假日。

实现

  1. 从百度API获取下一个月的假期

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    @Override
    public void initMonthHoliday(LocalDate date) {
    List<JsonObject> monthHoliday = getMonthHoliday(date);
    if (CollectionUtils.isEmpty(monthHoliday)) {
    return;
    }
    Map<Integer, Integer> holiday = new HashMap<>(monthHoliday.size());
    for (JsonObject jsonObject : monthHoliday) {
    String holidayDate = jsonObject.get("date").getAsString();
    LocalDate parse = LocalDate.parse(holidayDate,DateTimeFormatter.ofPattern("yyyy-M-d"));
    String dayOfMonth = parse.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
    //status 1 表示休息日,2 表示加班。
    String status = jsonObject.get("status").getAsString();
    holiday.put(Integer.valueOf(dayOfMonth), Integer.valueOf(status));
    }
    chineseHolidayMapper.insertIgnore(holiday);
    }

    @Override
    public Map<Integer, Boolean> getHoliday() {
    List<Map<String, Integer>> holiday = chineseHolidayMapper.getHoliday();
    return holiday.stream().collect(Collectors.toMap(bean -> bean.get("dayOfMonth"), bean -> "1".equals(bean.get("status"))? false : true));
    }

    /**
    *
    * 根据百度api,解析假期。
    * @date 2019年11月18日 11:17:02
    * @author lralin
    * @param date
    * @return java.util.List<com.google.gson.JsonObject>
    * @throws
    */
    private List<JsonObject> getMonthHoliday(LocalDate date) {
    String url = StringUtils.isBlank(holidayUrl) ? "https://sp0.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?query=%s&resource_id=6018" : holidayUrl;
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月");
    int monthValue = date.getMonthValue();
    log.info("日期:{}", date);
    JsonParser parser = new JsonParser();
    List<JsonObject> holidayList = new ArrayList<>();
    try {
    String run = OkhttpUtils.run(String.format(url, date.format(formatter)));
    log.info(run);
    JsonObject parse = parser.parse(run).getAsJsonObject();
    JsonObject data = parse.getAsJsonArray("data").get(0).getAsJsonObject();
    List<JsonObject> jsonObjectList = new ArrayList<>();
    analysisHoliday(data, jsonObjectList);
    for (JsonObject aJsonObjectList : jsonObjectList) {
    JsonArray list = aJsonObjectList.getAsJsonArray("list");
    for (int j = 0; j < list.size(); j++) {
    JsonObject listObj = list.get(j).getAsJsonObject();
    String s = listObj.get("date").getAsString();
    int baiduMonth = Integer.parseInt(s.split("-")[1]);
    if ((!holidayList.contains(listObj) && (baiduMonth == monthValue))) {
    holidayList.add(listObj);
    }
    }
    }
    } catch (IOException e) {
    log.error("节假日获取异常", e);
    }
    return holidayList;
    }

    /**
    *
    * 解析holiday字段
    * @date 2019年11月19日 08:40:24
    * @author lralin
    * @param data, jsonObjectList
    * @return void
    * @throws
    */
    private void analysisHoliday(JsonObject data, List<JsonObject> jsonObjectList) {
    //百度返回的格式不一样。
    getObject(data, jsonObjectList);
    getArray(data, jsonObjectList);
    }

    /**
    *
    * 返回是对象时的解析
    * @date 2019年11月19日 08:41:52
    * @author lralin
    * @param data, jsonObjectList
    * @return void
    * @throws
    */
    private void getArray(JsonObject data, List<JsonObject> jsonObjectList) {
    try {
    JsonArray jsonArr;
    if ((jsonArr = data.getAsJsonArray("holiday")) != null) {
    Iterator<JsonElement> iterator = jsonArr.iterator();
    while (iterator.hasNext()) {
    jsonObjectList.add(iterator.next().getAsJsonObject());
    }
    }
    } catch (ClassCastException ignored) {

    }
    }

    /**
    *
    * 返回是数组时的解析
    * @date 2019年11月19日 08:41:52
    * @author lralin
    * @param data, jsonObjectList
    * @return void
    * @throws
    */
    private void getObject(JsonObject data, List<JsonObject> jsonObjectList) {
    try {
    JsonObject obj;
    if ((obj = data.getAsJsonObject("holiday")) != null) {
    jsonObjectList.add(obj);
    }
    } catch (ClassCastException ignored) {

    }
    }

    使用定时任务0 15 23 L * ?(每月最后一天的23点15分触发 ),在每个月月底执行initMonthHoliday方法。把日期转换成int,插入到数据库。

  2. 在知道某个月的所有节假日之后,我们就能进行工作日计算了。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    import java.time.DayOfWeek;
    import java.time.LocalDate;
    import java.time.format.DateTimeFormatter;
    import java.util.HashMap;
    import java.util.Map;

    /**
    * 工作日加法计算
    *
    * @author lralin
    * @create 2019年11月19日 08:41:52
    **/
    public class WorkDaysUtils {

    private WorkDaysUtils() {
    }

    /**
    * 法定节假日map,true为补休,false为放假
    */
    private static final Map<Integer, Boolean> WORKDAY_MAP = new HashMap<>();

    /**
    * 初始化法定节假日map
    * 日期格式为yyyyMMdd,true为补休,false为放假,如果本来就是周末的节假日则不需再设置
    */
    public static void initWorkday(Map<Integer, Boolean> workdayMap) {
    //存储在数据库中百度API返回的假期数据,来初始化。
    WORKDAY_MAP.putAll(workdayMap);

    // 2018年的节假日
    // WORKDAY_MAP.put(20180101, false);
    // WORKDAY_MAP.put(20180211, true);
    // WORKDAY_MAP.put(20180215, false);
    // WORKDAY_MAP.put(20180216, false);
    // WORKDAY_MAP.put(20180219, false);
    // WORKDAY_MAP.put(20180220, false);
    // WORKDAY_MAP.put(20180221, false);
    // WORKDAY_MAP.put(20180224, true);
    // WORKDAY_MAP.put(20180405, false);
    // WORKDAY_MAP.put(20180406, false);
    // WORKDAY_MAP.put(20180408, true);
    // WORKDAY_MAP.put(20180428, true);
    // WORKDAY_MAP.put(20180430, false);
    // WORKDAY_MAP.put(20180501, false);
    // WORKDAY_MAP.put(20180618, false);
    // WORKDAY_MAP.put(20180924, false);
    // WORKDAY_MAP.put(20180929, true);
    // WORKDAY_MAP.put(20180930, true);
    // WORKDAY_MAP.put(20181001, false);
    // WORKDAY_MAP.put(20181002, false);
    // WORKDAY_MAP.put(20181003, false);
    // WORKDAY_MAP.put(20181004, false);
    // WORKDAY_MAP.put(20181005, false);
    }


    /**
    * 获取某日几个工作日之后的日期
    *
    * @param date, daysNum
    * @return java.time.LocalDate
    * @throws
    * @date 2019年11月18日 15:13:33
    * @author lralin
    */
    public static LocalDate getDate(LocalDate date, int daysNum) {
    int num = 0;
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
    while (num <= daysNum) {
    date = date.plusDays(1);
    boolean workDay = isWorkDay(date, formatter.format(date));
    if (workDay) {
    num++;
    }
    }
    return date;
    }

    private static boolean isWorkDay(LocalDate date, String dateStr) {
    Boolean isWorkDay = WORKDAY_MAP.get(Integer.valueOf(dateStr));
    if (isWorkDay != null) {
    // 如果在法定节假日map里有记录,则按此判断工作日
    return isWorkDay;
    } else {
    // 如果在法定节假日map里没记录,则按是否为周末判断工作日
    DayOfWeek dayOfWeek = date.getDayOfWeek();
    return (!DayOfWeek.SATURDAY.equals(dayOfWeek) && !DayOfWeek.SATURDAY.equals(dayOfWeek));
    }
    }

    }