JAVA节假日工具类服务分享(需联网)

2025-10-12 / 10 阅读 / Java

JAVA节假日工具类服务分享(需联网)

在 Java 开发中,处理节假日相关逻辑几乎是企业级应用的 “标配需求”—— 无论是计算订单生效周期、生成自动提醒日程,还是统计工作日数据,都离不开准确的节假日与调休信息支撑。但用过 Java 原生java.time包的开发者都清楚,标准库只提供了日期时间的基础处理能力,完全不包含节假日这类具有地域特性且动态变化的数据。

正是踩过这些坑后,我们最终确定了基于联网 API 的节假日工具类方案。通过对接可靠的公共节假日 API,既能直接获取权威的法定节假日名称、日期,还能精准识别调休工作日(如周末需上班的情况),甚至支持按年、按月、按日灵活查询。这种方式彻底解决了数据时效性问题,同时通过封装 HTTP 请求、JSON 解析和结果缓存逻辑,让业务层能以极简的方式调用。
接下来分享的工具类,就是基于这一思路实现的核心代码,包含了 API 对接、响应解析、异常处理等关键逻辑,可直接集成到 Spring Boot 等项目中使用。

 

节假日实体定义

package test;

import cn.hutool.core.date.DateUtil;

import java.util.Date;

/**
 * 节假日数据.
 *
 * @author wangbing
 * @version 0.0.1
 * @since 1.8
 */
public class HolidayData {

    /**
     * 工作日
     */
    public static final int WEEKDAY = 0;
    /**
     * 周末
     */
    public static final int WEEKEND = 1;
    /**
     * 节日
     */
    public static final int HOLIDAY = 2;
    /**
     * 调休(补班)
     */
    public static final int EXTRA_DAY = 3;

    public HolidayData() {
        this(DateUtil.date());
    }

    public HolidayData(String date) {
        this(DateUtil.parseDate(date));
    }

    public HolidayData(Date date) {
        this.type = DateUtil.isWeekend(date) ? WEEKEND : WEEKDAY;
        this.name = DateUtil.isWeekend(date) ? "周末" : "工作日";
        this.date = DateUtil.formatDate(date);
        this.holiday = false;
        this.workday = !DateUtil.isWeekend(date);
        this.weekend = DateUtil.isWeekend(date);
    }

    /**
     * 类型
     */
    private int type;

    /**
     * 说明
     */
    private String name;

    /**
     * 日期yyyy-MM-dd
     */
    private String date;

    /**
     * 是否节假日
     */
    private boolean holiday;

    /**
     * 是否工作日
     */
    private boolean workday;

    /**
     * 是否周末
     */
    private boolean weekend;

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

    public boolean isHoliday() {
        return holiday;
    }

    public void setHoliday(boolean holiday) {
        this.holiday = holiday;
    }

    public boolean isWorkday() {
        return workday;
    }

    public void setWorkday(boolean workday) {
        this.workday = workday;
    }

    public boolean isWeekend() {
        return weekend;
    }

    public void setWeekend(boolean weekend) {
        this.weekend = weekend;
    }
}

实现逻辑

package xyz.wbsite.jtask;

import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import xyz.wbsite.jmacro.util.DateUtil;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * 节假日服务提供者
 *
 * @author wangbing
 * @version 0.0.1
 * @since 1.8
 */
public class HolidayProvider {

    /**
     * 添加Hutool定时缓存,缓存有效期设为24小时
     */
    private final TimedCache<String, List<HolidayData>> holidayCache = CacheUtil.newTimedCache(24 * 60 * 60 * 1000);

    public List<HolidayData> getHolidayByYear(String year) {
        // 先从缓存获取
        List<HolidayData> cachedData = holidayCache.get(year);
        if (cachedData != null) {
            return cachedData;
        }

        // 缓存未命中,调用原方法获取数据
        List<HolidayData> freshData = pullFormTimor(year);

        // 存入缓存
        if (!freshData.isEmpty()) {
            holidayCache.put(year, freshData);
        }
        return freshData;
    }

    public List<HolidayData> getHolidayByMonth(String month) {
        List<HolidayData> result = new ArrayList<>();
        // 直接使用当前实例,移除Spring的LocalData.getBean调用
        List<HolidayData> holidayByYear = getHolidayByYear(month.substring(0, 4));
        for (HolidayData holidayData : holidayByYear) {
            if (holidayData.getDate().startsWith(month)) {
                result.add(holidayData);
            }
        }
        return result;
    }

    public HolidayData getHolidayByDate(String date) {
        // 直接使用当前实例,移除Spring的LocalData.getBean调用
        List<HolidayData> holidayByYear = getHolidayByYear(date.substring(0, 4));
        for (HolidayData holidayData : holidayByYear) {
            if (holidayData.getDate().equals(date)) {
                return holidayData;
            }
        }
        return new HolidayData(date);
    }

    /**
     * 是否节假日
     *
     * @param date 日期
     * @return 是否节假日
     */
    public boolean isHoliday(String date) {
        return getHolidayByDate(date).isHoliday();
    }

    /**
     * 是否工作日
     *
     * @param date 日期
     * @return 是否工作日
     */
    public boolean isWorkday(String date) {
        return getHolidayByDate(date).isWorkday();
    }

    /**
     * 是否周末
     *
     * @param date 日期
     * @return 是否周末
     */
    public boolean isWeekend(String date) {
        return getHolidayByDate(date).isWeekend();
    }

    /**
     * 提莫的神秘小站
     */
    private List<HolidayData> pullFormTimor(String year) {
        List<HolidayData> result = new ArrayList<>();
        try {
            String body = HttpUtil.get(StrUtil.format("http://timor.tech/api/holiday/year/{}", year));
            // {"code":"0","holiday":{"01-01":{"holiday":true,"name":"元旦","wage":3,"date":"2023-01-01"}...}}
            JSONObject entries = JSONUtil.parseObj(body);
            String rspCode = "code";
            if (entries.getInt(rspCode, -1) != 0) {
                return Collections.emptyList();
            }
            JSONObject holiday = entries.getJSONObject("holiday");
            for (Map.Entry<String, Object> entry : holiday) {
                JSONObject ho = (JSONObject) entry.getValue();
                HolidayData holidayData = new HolidayData();
                holidayData.setDate(ho.getStr("date"));
                holidayData.setName(ho.getStr("name"));
                // 判断是否为法定节假日
                holidayData.setHoliday(ho.getBool("holiday"));
                // 非法定节假日为工作日
                holidayData.setWorkday(!holidayData.isHoliday());
                // 是否为周末(周六周日),可以直接判断
                holidayData.setWeekend(DateUtil.isWeekend(DateUtil.parse(holidayData.getDate())));
                // 可以直接获取,但为了后期扩展,这里根据是否为法定节假日判断类型
                // 提莫的神秘小站返回的数据只有两种类型:法定节假日和调休(补班)
                holidayData.setType(holidayData.isHoliday() ? HolidayData.HOLIDAY : HolidayData.EXTRA_DAY);
                result.add(holidayData);
            }
        } catch (Exception e) {
            System.err.println("获取节假日数据失败: " + e.getMessage());
            return Collections.emptyList();
        }
        return result;
    }
}

以上代码直接引入即可使用,其中为了防止频繁调用api接口使用了hutool的缓存工具,如果不使用也是可以的,只需要将相关缓存代码删除即可。

相关推荐