LoginSignup
1
1

日本の祝日API【Deno KV / Deno Cron / Deno Deploy】

Last updated at Posted at 2024-01-27

今日が祝日かどうか

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);
    }
})
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1