每年获取一次各国假日日期,将其保存在集合中,再检查日期是否在集合中。对于 2026 年,这意味着全年只需一次请求,无需为每个日期单独请求。按照此规则,2026 年 11 月 27 日星期五是工作日;2026 年 11 月 26 日星期四是感恩节,不是工作日。工作日必须既不是星期六也不是星期日,且不在假日集合中。
使用 API 计算
GET /v1/calendars/holidays/{country}/{year} 返回全年数据。按国家和年份缓存返回的 date 字符串,使处理数千个日期的任务对每个国家和年份只发送一次请求。缓存中请同时保留国家和年份:使用的集合必须与传给函数的日期相符。
- 设置你的 API 密钥 获取免费密钥,并将其保存在
NARWHAL_API_KEY环境变量中。脚本读取该变量,并以Authorization: Bearer YOUR_KEY的形式将密钥发送到https://api.narwhalapi.com。 - 使用带缓存的 Python 函数 该函数将假日字符串保存在
frozenset中,并以国家和年份作为缓存参数。调用is_business_day时传入 Pythondate;默认国家为USA,遇到周末时会在查询假日前返回False。Python,带缓存的工作日检查import os from datetime import date from functools import lru_cache import requests HEADERS = {"Authorization": f"Bearer {os.environ['NARWHAL_API_KEY']}"} @lru_cache(maxsize=None) def holiday_dates(country: str, year: int) -> frozenset[str]: r = requests.get(f"https://api.narwhalapi.com/v1/calendars/holidays/{country}/{year}", headers=HEADERS, timeout=10) r.raise_for_status() return frozenset(h["date"] for h in r.json()["holidays"]) def is_business_day(day: date, country: str = "USA") -> bool: return day.weekday() < 5 and day.isoformat() not in holiday_dates(country, day.year) for d in (date(2026, 11, 26), date(2026, 11, 27), date(2026, 11, 28)): print(d, d.strftime("%a"), is_business_day(d)) - 在应用中使用 JavaScript 函数 在 JavaScript 中,映射为每个国家和年份保存一个集合,函数接受 ISO 日期字符串。需要默认
USA以外的日历时,请传入国家;日期加入缓存前会先处理响应状态。JavaScript (Node 18+),相同的检查const headers = { Authorization: `Bearer ${process.env.NARWHAL_API_KEY}` }; const cache = new Map(); async function holidayDates(country, year) { const key = `${country}-${year}`; if (!cache.has(key)) { const res = await fetch(`https://api.narwhalapi.com/v1/calendars/holidays/${country}/${year}`, { headers }); if (!res.ok) throw new Error(`Narwhal ${res.status}`); cache.set(key, new Set((await res.json()).holidays.map(h => h.date))); } return cache.get(key); } export async function isBusinessDay(isoDate, country = "USA") { const day = new Date(`${isoDate}T12:00:00Z`).getUTCDay(); if (day === 0 || day === 6) return false; return !(await holidayDates(country, Number(isoDate.slice(0, 4)))).has(isoDate); } console.log(await isBusinessDay("2026-11-26"), await isBusinessDay("2026-11-27"), await isBusinessDay("2026-11-28"));
Free 套餐每月有 5,000 次请求,因此任务处理大量日期时,应复用全年假日集合。
Python 缓存属于 holiday_dates;JavaScript 缓存是函数外部的 Map。两者都将假日日期保存在内存中以供复用。应用需要时,请添加刷新计划以及文件或数据库存储。要每月刷新当年数据并在重启后保留日期,需要为缓存查询补充这些功能。
使用电子表格或手动计算
在单独的工作表中保留 Holidays 列,并在公式中使用 Holidays 作为区域名称。将要判断的日期放在 A2 中。公式结合星期判断和该日期在假日区域中的出现次数,因此电子表格使用与脚本相同的工作日规则。假日列应与 API 缓存一样,包含所判断国家和年份的日期。使用公式判断其他日期时,请保留该列以供引用。
=AND(WEEKDAY(A2,2)<6, COUNTIF(Holidays, A2)=0)星期一至星期五的日期仅在 Holidays 区域中没有匹配日期时返回 TRUE。星期六或星期日即使不在该区域中,也会返回 FALSE。这种方式适合手动编辑假日日期的团队:列中保存日期,公式判断 A2 中的日期是否为工作日。
不同情况应选哪种方法
| 情况 | 最合适的方法 | 原因 |
|---|---|---|
| 脚本或服务 | 缓存的集合 | 在多次日期查询中复用全年假日日期 |
| 经常重启的应用 | 包含年份的文件或数据库表,每年刷新 | 在应用重启后保留假日集合 |
| 手动编辑日期的团队 | 电子表格中的一列 | 使用团队维护的假日日期 |
对于经常重启的应用,请将国家与年份、假日日期一起存储。根据待判断日期加载匹配的集合。持久化集合和内存集合使用相同的假日成员判断规则。
假日日期应缓存多久?
每月刷新当年数据,并在下一年数据发布后获取。假日日历很少变动,因此两次刷新之间可以复用全年集合。如果应用经常重启,请将该集合连同年份持久化到文件或数据库表中,并且每年刷新。
不要缓存失败的响应。两个脚本都会先处理失败响应,再存储假日日期。Basic 或 Pro 的 webhook 和数据流可通过 holiday.calendar.revised 事件通知日历修订。
日期应使用哪个时区?
使用市场所在时区的日历日期。UTC 午夜在美洲可能仍是前一天,因此传给函数的日历日期会影响结果。传给任一脚本前,请先确定市场当地的日期;假日集合包含日期字符串,是否匹配取决于所用的日期字符串。
Python 函数接受 date。JavaScript 函数接受 ISO 日期字符串,并使用其中的年份选择假日集合。两者都不接受市场时区参数。
如果该年的日历尚未发布怎么办?
API 会返回 404 calendar_not_published;请回退为仅按周末判断,并记录日志。在此回退方式中,星期六和星期日仍为非工作日,星期一至星期五则不查询假日,直接通过。由于假日日历不可用,此时工作日结果仅取决于周末规则。
两个函数都会在响应失败时抛出错误。请在应用处理该错误的位置添加仅按周末判断的回退逻辑,并且不要将尚未发布的响应存入假日缓存。错误参考请见 API 错误。
示例:2026 年感恩节当周
先使用 2026 年 11 月 26 日星期四和 2026 年的 USA 日历。当天是星期一至星期五中的一天,因此结果由假日集合成员检查决定。该日期是美国感恩节,因此工作日结果为 False。
再看 2026 年 11 月 27 日星期五。该日期通过了星期判断,且不在假日集合中,因此结果为 True。2026 年 11 月 28 日星期六未通过星期判断,无需查询假日便返回 False。
| 日期 | 星期 | 工作日 | 原因 |
|---|---|---|---|
| 2026年11月26日 | 星期四 | False | 美国感恩节 |
| 2026年11月27日 | 星期五 | True | 星期一至星期五,且不在假日集合中 |
| 2026年11月28日 | 星期六 | False | 周末 |
2026-11-26 Thu False
2026-11-27 Fri True
2026-11-28 Sat Falsefalse true false发布于。
