【Java 实战】用java解析节假日通知!自动生成全年放假与调休 JSON!
每年年底,国务院都会发布次年的《节假日放假安排通知》。如果你想做一个日历系统、排班系统、OA 考勤系统、节日提醒工具,就离不开“节假日 + 调休日期”的数据。
·
💡 前言
每年年底,都会发布次年的《节假日放假安排通知》。
如果你想做一个日历系统、排班系统、OA 考勤系统、节日提醒工具,
就离不开“节假日 + 调休日期”的数据。
但问题是——通知是自然语言写的,格式复杂、跨年、混合多个节日,手动录入太麻烦!
于是,我写了一个超级实用的小工具——
👉 Java 自动解析节假日通知,一键生成标准 JSON 数据。
🎯 功能介绍
✅ 自动识别每个节假日名称(春节、国庆节、中秋节等)
✅ 自动解析「放假区间」、「上班补班日」
✅ 支持跨月、跨年解析(如春节、国庆节)
✅ 自动去重、日期排序
✅ 一键输出 JSON(可直接导入前端项目或数据库)
🧩 示例输入
下面是一段国务院官方通知示例(2025 年)👇
国务院办公厅关于2025年部分节假日安排的通知
一、元旦:1月1日(周三)放假1天,不调休。
二、春节:1月28日(农历除夕、周二)至2月4日(农历正月初七、周二)放假调休,共8天。1月26日(周日)、2月8日(周六)上班。
三、清明节:4月4日(周五)至6日(周日)放假,共3天。
四、劳动节:5月1日(周四)至5日(周一)放假调休,共5天。4月27日(周日)上班。
五、端午节:5月31日(周六)至6月2日(周一)放假,共3天。
六、国庆节、中秋节:10月1日(周三)至8日(周三)放假调休,共8天。9月28日(周日)、10月11日(周六)上班。
💻 Java 代码(完整可运行)
文件名:HolidaysParseFinal.java
package org.dromara;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.*;
/**
* HolidaysParseFinal:国务院节假日解析最终版
* ✅ 支持:
* - 跨年日期
* - "至6日" 自动补全月份
* - 去重、日期排序
* - 输出 JSON 格式
*/
public class HolidaysParseFinal {
public static void main(String[] args) {
String text_bak = """
国务院办公厅关于2025年部分节假日安排的通知
一、元旦:1月1日(周三)放假1天,不调休。
二、春节:1月28日(农历除夕、周二)至2月4日(农历正月初七、周二)放假调休,共8天。1月26日(周日)、2月8日(周六)上班。
三、清明节:4月4日(周五)至6日(周日)放假,共3天。
四、劳动节:5月1日(周四)至5日(周一)放假调休,共5天。4月27日(周日)上班。
五、端午节:5月31日(周六)至6月2日(周一)放假,共3天。
六、国庆节、中秋节:10月1日(周三)至8日(周三)放假调休,共8天。9月28日(周日)、10月11日(周六)上班。
""";
String text= """
今天(4日),国务院办公厅发布关于2026年部分节假日安排的通知。
一、元旦:1月1日(周四)至3日(周六)放假调休,共3天。1月4日(周日)上班。
二、春节:2月15日(农历腊月二十八、周日)至23日(农历正月初七、周一)放假调休,共9天。2月14日(周六)、2月28日(周六)上班。
三、清明节:4月4日(周六)至6日(周一)放假,共3天。
四、劳动节:5月1日(周五)至5日(周二)放假调休,共5天。5月9日(周六)上班。
五、端午节:6月19日(周五)至21日(周日)放假,共3天。
六、中秋节:9月25日(周五)至27日(周日)放假,共3天。
七、国庆节:10月1日(周四)至7日(周三)放假调休,共7天。9月20日(周日)、10月10日(周六)上班。
""";
List<Holiday> list = HolidaysParse.parseHolidaysJson("2026", text);
// 去重 + 排序
Map<String, Holiday> unique = new HashMap<>();
for (Holiday h : list) {
String key = (h.isHoliday ? "H-" : "W-") + sdf.format(h.date);
if (unique.containsKey(key)) continue;
unique.put(key, h);
}
List<Holiday> out = new ArrayList<>(unique.values());
out.sort(Comparator.comparing(h -> h.date));
System.out.println("==== 解析结果 ====");
for (Holiday h : out) {
System.out.println((h.isHoliday ? "假期:" : "上班:") + h.name + " - " + fmt(h.date));
}
// ✅ JSON 输出
System.out.println("\n==== JSON ====");
System.out.println(toJson(out));
}
static class Holiday {
String name;
Date date;
boolean isHoliday;
Holiday(String name, Date date, boolean isHoliday) {
this.name = name;
this.date = date;
this.isHoliday = isHoliday;
}
}
static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
static String fmt(Date d) { return sdf.format(d); }
// ✅ JSON 输出方法
public static String toJson(List<Holiday> list) {
StringBuilder sb = new StringBuilder();
sb.append("[\n");
for (int i = 0; i < list.size(); i++) {
Holiday h = list.get(i);
sb.append(" {\"name\": \"").append(h.name)
.append("\", \"date\": \"").append(fmt(h.date))
.append("\", \"type\": \"").append(h.isHoliday ? "holiday" : "workday")
.append("\"}");
if (i != list.size() - 1) sb.append(",");
sb.append("\n");
}
sb.append("]");
return sb.toString();
}
// ================= 核心解析逻辑 =================
public static class HolidaysParse {
private static final Pattern SECTION_PATTERN = Pattern.compile("(?ms)([一二三四五六七八九十]+、.*?)(?=\\n[一二三四五六七八九十]+、|\\z)");
private static final Pattern RANGE_FULL_YEAR = Pattern.compile("(\\d{4}年\\d{1,2}月\\d{1,2}日)至(\\d{4}年\\d{1,2}月\\d{1,2}日)放假");
private static final Pattern RANGE_NORMAL = Pattern.compile("(\\d{1,2}月\\d{1,2}日)至(\\d{1,2}月\\d{1,2}日)放假");
private static final Pattern RANGE_END_DAY_ONLY = Pattern.compile("(\\d{1,2}月\\d{1,2}日)至(\\d{1,2}日)放假");
private static final Pattern SINGLE_DAY = Pattern.compile("(\\d{1,2}月\\d{1,2}日)放假");
private static final Pattern WORKDAY = Pattern.compile("((?:\\d{1,2}月\\d{1,2}日[、,,]?)+)上班");
private static final Pattern YEAR_DATE = Pattern.compile("(\\d{4})年(\\d{1,2})月(\\d{1,2})日");
public static List<Holiday> parseHolidaysJson(String year, String text) {
String norm = text.replaceAll("(.*?)", "").replaceAll("\\r", "");
List<Holiday> result = new ArrayList<>();
Matcher sectionMatcher = SECTION_PATTERN.matcher(norm);
while (sectionMatcher.find()) {
String section = sectionMatcher.group(1).trim();
if (section.isEmpty()) continue;
String name = extractNameFromSection(section);
if (name.isEmpty()) name = "未知假期";
Matcher mFullYear = RANGE_FULL_YEAR.matcher(section);
while (mFullYear.find()) {
String start = convertYearDateToYMD(mFullYear.group(1));
String end = convertYearDateToYMD(mFullYear.group(2));
addRange(result, name, start, end, true);
}
Matcher mNormal = RANGE_NORMAL.matcher(section);
while (mNormal.find()) {
String start = year + "-" + mNormal.group(1).replace("月", "-").replace("日", "");
String end = year + "-" + mNormal.group(2).replace("月", "-").replace("日", "");
addRange(result, name, start, end, true);
}
Matcher mEndDay = RANGE_END_DAY_ONLY.matcher(section);
while (mEndDay.find()) {
Matcher mm = Pattern.compile("(\\d{1,2})月(\\d{1,2})日").matcher(mEndDay.group(1));
if (mm.find()) {
String month = mm.group(1);
String start = year + "-" + month + "-" + mm.group(2);
String end = year + "-" + month + "-" + mEndDay.group(2).replace("日", "");
addRange(result, name, start, end, true);
}
}
Matcher mSingle = SINGLE_DAY.matcher(section);
while (mSingle.find()) {
String d = year + "-" + mSingle.group(1).replace("月", "-").replace("日", "");
result.add(new Holiday(name, parseDate(d), true));
}
Matcher mWork = WORKDAY.matcher(section);
while (mWork.find()) {
Matcher mDay = Pattern.compile("(\\d{1,2}月\\d{1,2}日)").matcher(mWork.group(1));
while (mDay.find()) {
String d = year + "-" + mDay.group(1).replace("月", "-").replace("日", "");
result.add(new Holiday(name, parseDate(d), false));
}
}
}
Map<String, Holiday> dedup = new HashMap<>();
for (Holiday h : result) {
String key = sdf.format(h.date);
if (!dedup.containsKey(key)) dedup.put(key, h);
else if (!dedup.get(key).isHoliday && h.isHoliday) dedup.put(key, h);
}
List<Holiday> finalList = new ArrayList<>(dedup.values());
finalList.sort(Comparator.comparing(h -> h.date));
return finalList;
}
private static void addRange(List<Holiday> out, String name, String startYmd, String endYmd, boolean isHoliday) {
for (String d : rangeDate(startYmd, endYmd)) {
out.add(new Holiday(name, parseDate(d), isHoliday));
}
}
private static String extractNameFromSection(String section) {
int colon = section.indexOf(":");
if (colon == -1) colon = section.indexOf(":");
if (colon == -1) return "";
String left = section.substring(0, colon);
return left.replaceAll("^[一二三四五六七八九十]+、?", "").trim();
}
private static String convertYearDateToYMD(String s) {
Matcher m = YEAR_DATE.matcher(s);
if (m.find()) return m.group(1) + "-" + two(m.group(2)) + "-" + two(m.group(3));
return s.replace("年", "-").replace("月", "-").replace("日", "");
}
private static String two(String v) { return v.length() == 1 ? "0" + v : v; }
private static Date parseDate(String s) {
try { return sdf.parse(s); }
catch (ParseException e) { throw new RuntimeException(e); }
}
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
private static List<String> rangeDate(String start, String end) {
List<String> res = new ArrayList<>();
try {
Date s = sdf.parse(start), e = sdf.parse(end);
Calendar c = Calendar.getInstance(); c.setTime(s);
while (!c.getTime().after(e)) {
res.add(sdf.format(c.getTime()));
c.add(Calendar.DATE, 1);
}
} catch (Exception ex) { ex.printStackTrace(); }
return res;
}
}
}
🧾 输出示例

==== 解析结果 ====
假期:元旦 - 2026-01-01
假期:元旦 - 2026-01-02
假期:元旦 - 2026-01-03
上班:元旦 - 2026-01-04
上班:春节 - 2026-02-14
假期:春节 - 2026-02-15
假期:春节 - 2026-02-16
假期:春节 - 2026-02-17
假期:春节 - 2026-02-18
假期:春节 - 2026-02-19
假期:春节 - 2026-02-20
假期:春节 - 2026-02-21
假期:春节 - 2026-02-22
假期:春节 - 2026-02-23
上班:春节 - 2026-02-28
假期:清明节 - 2026-04-04
假期:清明节 - 2026-04-05
假期:清明节 - 2026-04-06
假期:劳动节 - 2026-05-01
假期:劳动节 - 2026-05-02
假期:劳动节 - 2026-05-03
假期:劳动节 - 2026-05-04
假期:劳动节 - 2026-05-05
上班:劳动节 - 2026-05-09
假期:端午节 - 2026-06-19
假期:端午节 - 2026-06-20
假期:端午节 - 2026-06-21
上班:国庆节 - 2026-09-20
假期:中秋节 - 2026-09-25
假期:中秋节 - 2026-09-26
假期:中秋节 - 2026-09-27
假期:国庆节 - 2026-10-01
假期:国庆节 - 2026-10-02
假期:国庆节 - 2026-10-03
假期:国庆节 - 2026-10-04
假期:国庆节 - 2026-10-05
假期:国庆节 - 2026-10-06
假期:国庆节 - 2026-10-07
上班:国庆节 - 2026-10-10
==== JSON ====
[
{"name": "元旦", "date": "2026-01-01", "type": "holiday"},
{"name": "元旦", "date": "2026-01-02", "type": "holiday"},
{"name": "元旦", "date": "2026-01-03", "type": "holiday"},
{"name": "元旦", "date": "2026-01-04", "type": "workday"},
{"name": "春节", "date": "2026-02-14", "type": "workday"},
{"name": "春节", "date": "2026-02-15", "type": "holiday"},
{"name": "春节", "date": "2026-02-16", "type": "holiday"},
{"name": "春节", "date": "2026-02-17", "type": "holiday"},
{"name": "春节", "date": "2026-02-18", "type": "holiday"},
{"name": "春节", "date": "2026-02-19", "type": "holiday"},
{"name": "春节", "date": "2026-02-20", "type": "holiday"},
{"name": "春节", "date": "2026-02-21", "type": "holiday"},
{"name": "春节", "date": "2026-02-22", "type": "holiday"},
{"name": "春节", "date": "2026-02-23", "type": "holiday"},
{"name": "春节", "date": "2026-02-28", "type": "workday"},
{"name": "清明节", "date": "2026-04-04", "type": "holiday"},
{"name": "清明节", "date": "2026-04-05", "type": "holiday"},
{"name": "清明节", "date": "2026-04-06", "type": "holiday"},
{"name": "劳动节", "date": "2026-05-01", "type": "holiday"},
{"name": "劳动节", "date": "2026-05-02", "type": "holiday"},
{"name": "劳动节", "date": "2026-05-03", "type": "holiday"},
{"name": "劳动节", "date": "2026-05-04", "type": "holiday"},
{"name": "劳动节", "date": "2026-05-05", "type": "holiday"},
{"name": "劳动节", "date": "2026-05-09", "type": "workday"},
{"name": "端午节", "date": "2026-06-19", "type": "holiday"},
{"name": "端午节", "date": "2026-06-20", "type": "holiday"},
{"name": "端午节", "date": "2026-06-21", "type": "holiday"},
{"name": "国庆节", "date": "2026-09-20", "type": "workday"},
{"name": "中秋节", "date": "2026-09-25", "type": "holiday"},
{"name": "中秋节", "date": "2026-09-26", "type": "holiday"},
{"name": "中秋节", "date": "2026-09-27", "type": "holiday"},
{"name": "国庆节", "date": "2026-10-01", "type": "holiday"},
{"name": "国庆节", "date": "2026-10-02", "type": "holiday"},
{"name": "国庆节", "date": "2026-10-03", "type": "holiday"},
{"name": "国庆节", "date": "2026-10-04", "type": "holiday"},
{"name": "国庆节", "date": "2026-10-05", "type": "holiday"},
{"name": "国庆节", "date": "2026-10-06", "type": "holiday"},
{"name": "国庆节", "date": "2026-10-07", "type": "holiday"},
{"name": "国庆节", "date": "2026-10-10", "type": "workday"}
]
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐

所有评论(0)