节假日查询:一键生成全年放假日历,894-4 假日列表实战
# 节假日查询:一键生成全年放假日历,894-4 假日列表实战
> 接口 894(接入点 894-4 假日列表) · 免费 · POST/GET · 返回 JSON · 适用人群:全栈工程师、日历开发者 · 阅读时间:约 7 分钟
## TL;DR
- 894-4 一条请求返回**整年**节假日数组,每条含起止日期、名称、描述、调修日。
- 把 `data` 与 `inverse_days` 拼起来,就能渲染「放假 + 补班」二维日历。
- 数据一年只变一次,强烈建议缓存整年结果(见 [缓存策略设计](https://www.showapi.com/guides/holiday-query-cache-894))。
## Why:做日历应用的第一步
日历、排班、请假、考勤系统都需要一份"全年哪天放假、哪天补班"的基准表。894-4 直接给你结构化数组,你只需遍历渲染,不用手维护 Excel。
## What:接口速览
| 项 | 说明 |
|----|------|
| 接入点 | **894-4 假日列表** |
| 接口地址 | `https://route.showapi.com/894-4?appKey=YOUR_APPKEY` |
| 请求方式 | POST / GET |
| 计费 | 免费服务(有档位限制) |
| 更新频率 | 每年更新,国务院文件发布后一周内更新 |
**请求参数**:`year`(String,否,默认当年)。
## How:生成全年日历
### 步骤 1:拉取全年数据
**Python(requests)**
```python
import requests
def get_year_holidays(year: str, appkey: str):
url = "https://route.showapi.com/894-4"
r = requests.post(url, params={"appKey": appkey, "year": year}, timeout=15)
body = r.json()
if str(body["showapi_res_body"]["ret_code"]) != "0":
raise RuntimeError(body.get("showapi_res_error"))
return body["showapi_res_body"]["data"]
holidays = get_year_holidays("2026", "YOUR_APPKEY")
for h in holidays:
makeup = ", ".join(h.get("inverse_days") or [])
print(f"{h['holiday']}: {h['begin']}~{h['end']} | 调休上班: {makeup or '无'}")
```
**Node.js(fetch)**
```javascript
const res = await fetch("https://route.showapi.com/894-4?appKey=YOUR_APPKEY&year=2026",
{ method: "POST", timeout: 15000 });
const body = await res.json();
if (String(body.showapi_res_body.ret_code) !== "0") throw new Error(body.showapi_res_error);
const holidays = body.showapi_res_body.data;
for (const h of holidays) console.log(h.holiday, h.begin, "~", h.end);
```
**cURL**
```bash
curl -X POST "https://route.showapi.com/894-4?appKey=YOUR_APPKEY" \
-H "content-type: application/x-www-form-urlencoded" -d "year=2026"
```
### 步骤 2:拼出「放假 + 补班」二维表
```python
from datetime import date, timedelta
def daterange(s, e):
s = date(int(s[:4]), int(s[4:6]), int(s[6:8]))
e = date(int(e[:4]), int(e[4:6]), int(e[6:8]))
while s <= e:
yield s; s += timedelta(days=1)
# 放假区间
off_days = set()
for h in holidays:
for d in daterange(h["begin"], h["end"]):
off_days.add(d)
# 补班日(来自每条的 inverse_days,仅 2021 后)
makeup_days = set()
for h in holidays:
for md in (h.get("inverse_days") or []):
makeup_days.add(date(int(md[:4]), int(md[4:6]), int(md[6:8])))
print("放假天数:", len(off_days), "| 补班天数:", len(makeup_days))
```
## 返回示例与解析
```json
{
"showapi_res_body": {
"ret_code": "0",
"data": [
{ "holiday": "劳动节", "begin": "20250501", "end": "20250505",
"holiday_remark": "5月1日(周四)至5日(周一)放假调休,共5天。4月27日(周日)上班。",
"inverse_days": ["20250427"] }
]
}
}
```
| 字段 | 说明 |
|------|------|
| data[].begin / end | 起止日期 `YYYYMMDD` |
| data[].holiday | 节假日名称 |
| data[].holiday_remark | 描述,含调休说明 |
| data[].inverse_days | 调修日 `String[]`,仅 2021 年后有值 |
## 进阶 / 边界
- **inverse_days 是字符串数组**:注意与 894-7 的 `inverse_days`(对象数组)结构不同。
- **补班日可能落在节假日描述里**:`holiday_remark` 文本也会写"X月X日上班",但结构化数据以 `inverse_days` 为准。
- **缓存整年**:数据一年只更新一次,把整年结果缓存到 Redis/本地,次年再刷新。详见 [缓存策略设计](https://www.showapi.com/guides/holiday-query-cache-894)。
## FAQ
**Q1:inverse_days 为什么有时是空的?**
A:仅 2021 年之后的数据有调修日值;更早年份或该节日无调休时为空数组。
**Q2:year 传 2026 和传 "2026" 有区别吗?**
A:文档定义为 String,建议传字符串 `"2026"`,避免某些客户端把数字当整数导致格式问题。
**Q3:怎么知道某天补班?**
A:遍历所有 `data[].inverse_days` 汇总成集合即为全年补班日;或用 [894-7 调休日列表](https://www.showapi.com/guides/holiday-query-makeup-days-894)。
**Q4:整年数据要每次都拉吗?**
A:不用。一年只变一次,缓存整年结果即可。
**Q5:ret_code 是字符串还是数字?**
A:894-4 是字符串 `"0"`,判成功统一用 `str(...)`。
## 相关能力 / 下一步阅读
- [节假日查询:5 分钟接入,从注册到拿到全年放假安排](https://www.showapi.com/guides/holiday-query-quickstart-894)
- [节假日查询:调休上班日怎么算?894-7 调休日列表查询实战](https://www.showapi.com/guides/holiday-query-makeup-days-894)
- [节假日查询:免费接口也要省调用,节假日数据缓存策略设计](https://www.showapi.com/guides/holiday-query-cache-894)
- **本系列共 12 篇**:查看[节假日查询指南总目录](https://www.showapi.com/guides/holiday-query-guides-894)