今日が祝日かどうか
curl https://holiday.deno.dev
特定の日が祝日かどうか
curl https://holiday.deno.dev/20240101
curl https://holiday.deno.dev/2024-01-01
明日が祝日かどうか
# 明日
curl https://holiday.deno.dev/tomorrow
# 昨日
curl https://holiday.deno.dev/yesterday
# 明後日
curl https://holiday.deno.dev/2
# 一昨日
curl https://holiday.deno.dev/-2
# 一週間後
curl https://holiday.deno.dev/7
ケンオール互換API
# 全ての祝日
curl https://holiday.deno.dev/kenall.json
# 2024年の祝日
curl https://holiday.deno.dev/kenall.json?year=2024
# 2024年11月03日以降の祝日
curl https://holiday.deno.dev/kenall.json?from=2024-11-03
# 2023年11月03日以降の2023年の祝日
curl "https://holiday.deno.dev/kenall.json?from=2023-11-03&year=2023"
# 1955年01月15日以前の祝日
curl https://holiday.deno.dev/kenall.json?to=1955-01-15
# 1956年01月15日以前の1956年の祝日
curl "https://holiday.deno.dev/kenall.json?to=1956-01-15&year=1956"
# 2024年09月16日から2024年11月03日までの祝日
curl "https://holiday.deno.dev/kenall.json?from=2024-09-16&to=2024-11-03"
# 3件の祝日
curl https://holiday.deno.dev/kenall.json?limit=3
# 逆順の祝日
curl https://holiday.deno.dev/kenall.json?reverse
Holidays JP 互換API
# 全ての祝日
curl https://holiday.deno.dev/list.json
# 2024年の祝日
curl https://holiday.deno.dev/list.json?year=2024
# 2024年11月03日以降の祝日
curl https://holiday.deno.dev/list.json?from=2024-11-03
# 2023年11月03日以降の2023年の祝日
curl "https://holiday.deno.dev/list.json?from=2023-11-03&year=2023"
# 1955年01月15日以前の祝日
curl https://holiday.deno.dev/list.json?to=1955-01-15
# 1956年01月15日以前の1956年の祝日
curl "https://holiday.deno.dev/list.json?to=1956-01-15&year=1956"
# 2024年09月16日から2024年11月03日までの祝日
curl "https://holiday.deno.dev/list.json?from=2024-09-16&to=2024-11-03"
# 3件の祝日
curl https://holiday.deno.dev/list.json?limit=3
# 逆順の祝日
curl https://holiday.deno.dev/list.json?reverse
CSV API
curl https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv | iconv -f CP932 -t UTF8
JavaScript実装例
See the Pen Untitled by John Doe (@04) on CodePen.
ソースコード
Deno Cronで毎日最新版に更新してます。
import Encoding from "npm:encoding-japanese"
const headers = { 'Access-Control-Allow-Origin': '*' }
const kv = await Deno.openKv()
Deno.serve(async (req: Request) => {
const url = new URL(req.url)
const path = url.pathname.slice(1)
if (path === '') {
/**
* @example
* // 今日の祝日
* https://holiday.deno.dev/
*/
const today = new Date()
// JSTに変換する。
today.setHours(today.getHours() + 9)
const holiday = await kv.get([today.getFullYear(), today.getMonth()+1, today.getDate()])
return new Response(holiday.value, { headers })
} else if (/^\d{4}-?\d{2}-?\d{2}$/.test(path)) {
/**
* @example
* // 元旦
* https://holiday.deno.dev/20240101
* https://holiday.deno.dev/2024-01-01
*/
const holiday = await kv.get(path.match(/(\d{4})-?(\d{2})-?(\d{2})/).slice(1).map(s => Number(s)))
return new Response(holiday.value, { headers })
} else if (['yesterday', 'tomorrow'].includes(path) || !isNaN(path)) {
/**
* @example
* // 明日の祝日
* https://holiday.deno.dev/tomorrow
* // 昨日の祝日
* https://holiday.deno.dev/yesterday
* // 明後日の祝日
* https://holiday.deno.dev/2
* // 一昨日の祝日
* https://holiday.deno.dev/-2
*/
let delta
if (path === 'yesterday') delta = -1
else if (path === 'tomorrow') delta = 1
else delta = Number(path)
const date = new Date()
date.setDate(date.getDate() + delta)
// JSTに変換する。
date.setHours(date.getHours() + 9)
const holiday = await kv.get([date.getFullYear(), date.getMonth()+1, date.getDate()])
return new Response(holiday.value, { headers })
} else if (path === 'list.json') {
/**
* @example
* // 全ての祝日
* https://holiday.deno.dev/list.json
* // 2024年の祝日
* https://holiday.deno.dev/list.json?year=2024
* // 2024年11月03日以降の祝日
* https://holiday.deno.dev/list.json?from=2024-11-03
* // 2023年11月03日以降の2023年の祝日
* https://holiday.deno.dev/list.json?from=2023-11-03&year=2023
* // 1955年01月15日以前の祝日
* https://holiday.deno.dev/list.json?to=1955-01-15
* // 1956年01月15日以前の1956年の祝日
* https://holiday.deno.dev/list.json?to=1956-01-15&year=1956
* // 2024年09月16日から2024年11月03日までの祝日
* https://holiday.deno.dev/list.json?from=2024-09-16&to=2024-11-03
* // 3件の祝日
* https://holiday.deno.dev/list.json?limit=3
* // 逆順の祝日
* https://holiday.deno.dev/list.json?reverse
*/
const params = { prefix: [] }
const options = {}
if (url.searchParams.has('year')) {
params.prefix = [Number(url.searchParams.get('year'))]
}
if (url.searchParams.has('from') && url.searchParams.has('to')) {
delete params.prefix
params.start = url.searchParams.get('from').split('-').map(s=>Number(s))
params.end = url.searchParams.get('to').split('-').map(s=>Number(s))
/**
* 指定した日を含める。
* @see {@link https://docs.deno.com/deploy/kv/manual/operations#list}
*/
params.end[2]++
} else if (url.searchParams.has('from')) {
params.start = url.searchParams.get('from').split('-').map(s=>Number(s))
} else if (url.searchParams.has('to')) {
params.end = url.searchParams.get('to').split('-').map(s=>Number(s))
/**
* 指定した日を含める。
* @see {@link https://docs.deno.com/deploy/kv/manual/operations#list}
*/
params.end[2]++
}
if (url.searchParams.has('limit')) {
options.limit = Number(url.searchParams.get('limit'))
}
if (url.searchParams.has('reverse')) {
options.reverse = true
}
const iter = kv.list<string>(params, options)
const holidays = []
for await (const res of iter) holidays.push(res)
return Response.json(Object.fromEntries(holidays.map(({key: [year, month, day], value}) => [new Date(year, month - 1, day).toLocaleDateString('sv'), value])), { headers })
} else if (path === 'kenall.json') {
/**
* 日本の祝日API
*
* @example
* // 全ての祝日
* https://holiday.deno.dev/kenall.json
* // 2024年の祝日
* https://holiday.deno.dev/kenall.json?year=2024
* // 2024年11月03日以降の祝日
* https://holiday.deno.dev/kenall.json?from=2024-11-03
* // 2023年11月03日以降の2023年の祝日
* https://holiday.deno.dev/kenall.json?from=2023-11-03&year=2023
* // 1955年01月15日以前の祝日
* https://holiday.deno.dev/kenall.json?to=1955-01-15
* // 1956年01月15日以前の1956年の祝日
* https://holiday.deno.dev/kenall.json?to=1956-01-15&year=1956
* // 2024年09月16日から2024年11月03日までの祝日
* https://holiday.deno.dev/kenall.json?from=2024-09-16&to=2024-11-03
* // 3件の祝日
* https://holiday.deno.dev/kenall.json?limit=3
* // 逆順の祝日
* https://holiday.deno.dev/kenall.json?reverse
*
* @see {@link https://kenall.jp/docs/API/holidays/}
*/
const params = { prefix: [] }
const options = {}
if (url.searchParams.has('year')) {
params.prefix = [Number(url.searchParams.get('year'))]
}
if (url.searchParams.has('from') && url.searchParams.has('to')) {
delete params.prefix
params.start = url.searchParams.get('from').split('-').map(s=>Number(s))
params.end = url.searchParams.get('to').split('-').map(s=>Number(s))
/**
* 指定した日を含める。
* @see {@link https://docs.deno.com/deploy/kv/manual/operations#list}
*/
params.end[2]++
} else if (url.searchParams.has('from')) {
params.start = url.searchParams.get('from').split('-').map(s=>Number(s))
} else if (url.searchParams.has('to')) {
params.end = url.searchParams.get('to').split('-').map(s=>Number(s))
/**
* 指定した日を含める。
* @see {@link https://docs.deno.com/deploy/kv/manual/operations#list}
*/
params.end[2]++
}
if (url.searchParams.has('limit')) {
options.limit = Number(url.searchParams.get('limit'))
}
if (url.searchParams.has('reverse')) {
options.reverse = true
}
const iter = kv.list<string>(params, options)
const holidays = []
for await (const res of iter) holidays.push(res)
return Response.json({
data: holidays.map(({key: [year, month, day], value: title}) => {
const date = new Date(year, month - 1, day)
return {
title,
date: date.toLocaleDateString('sv'),
day_of_week: date.getDay(),
day_of_week_text: date.toLocaleString('en', {weekday:'long'}).toLowerCase()
}
})
}, { headers })
}
return new Response('', { headers })
})
Deno.cron("sample cron", "0 0 * * *", async () => {
/**
* 「国民の祝日」について
* @see {@link https://www8.cao.go.jp/chosei/shukujitsu/gaiyou.html#syukujitu}
*/
const buffer = await fetch('https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv').then(r=>r.arrayBuffer())
/**
* Convert character encoding from CP932 to UNICODE.
* @see {@link https://github.com/polygonplanet/encoding.js#example-usage}
*/
const csv = Encoding.codeToString(Encoding.convert(new Uint8Array(buffer), { from: 'CP932', to: 'UNICODE' }))
// 行ごとに分割し、ヘッダーを削除し、空行を削除し、列を分割する。
const holidays = csv.split('\r\n').slice(1).filter(line=>line).map(line => line.split(','))
for await (const [date, name] of holidays) {
await kv.set(date.split('/').map(s=>Number(s)), name);
}
})