0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

祝日判定を自作したら、内閣府の CSV との突き合わせで「2003年5月4日」だけズレていた話(JavaScript)

0
Posted at

営業日の計算のために、日本の祝日判定を JavaScript で自作しました。振替休日も国民の休日も入れたし大丈夫だろう、と思いつつ、内閣府が公開している祝日一覧の CSV と全件を突き合わせてみたところ、1日だけズレが見つかりました。その原因と、突き合わせの方法を紹介します。

この記事は、生成AI(Claude)を使って書いた下書きを、実際に動かして確認してから投稿しています。

突き合わせの方法

内閣府は祝日の一覧を CSV で公開しています(Shift_JIS、国民の祝日について からリンク)。行は 2026/5/6,休日 のような形式です。

ブラウザで内閣府のページを開いたまま開発者ツールで実行すると、同じサイトなので CSV をそのまま fetch できます。holidays(y) は自作の関数で、その年の祝日・休日を 'YYYY-MM-DD' をキーにした Map で返すものです。

const pad = n => String(n).padStart(2, '0');
const buf = await (await fetch('/chosei/shukujitsu/syukujitsu.csv')).arrayBuffer();
const text = new TextDecoder('shift_jis').decode(buf);
const official = new Set(text.trim().split(/\r?\n/).slice(1)
  .map(line => line.split(',')[0].split('/').map(Number))
  .filter(([y]) => y >= 2000)
  .map(([y, m, d]) => `${y}-${pad(m)}-${pad(d)}`));

const mine = new Set();
for (let y = 2000; y <= 2027; y++) for (const k of holidays(y).keys()) mine.add(k);

console.log({
  missing: [...official].filter(k => !mine.has(k)), // 公式にあって自分にない
  extra: [...mine].filter(k => !official.has(k)),   // 自分にあって公式にない
});

結果: extra: ['2003-05-04']

公式にない日が1日だけ、自分の結果に入っていました。2003年5月4日です。

2006年までは、5月4日は祝日ではなく「国民の休日」でした(憲法記念日とこどもの日に挟まれるため)。ところが 2003年5月4日は日曜日です。当時の条文は、国民の休日から日曜日を除いていたため、内閣府の一覧には載っていません。

自作の関数は「前日と翌日が祝日なら休日」とだけ判定していたので、日曜日も休日として数えていました。

// 国民の休日: 前日と翌日が本来の祝日である、祝日でない日(日曜日は除く)
for (let d = new Date(y, 0, 2); d.getFullYear() === y; d.setDate(d.getDate() + 1)) {
  if (d.getDay() === 0) continue; // ← これが抜けていた
  const prev = new Date(d.getFullYear(), d.getMonth(), d.getDate() - 1);
  const next = new Date(d.getFullYear(), d.getMonth(), d.getDate() + 1);
  if (!all.has(ymd(d)) && law.has(ymd(prev)) && law.has(ymd(next))) all.set(ymd(d), '国民の休日');
}

どうせ休みの日なので営業日の計算には影響しませんが、祝日一覧を画面に出すと1日多くなります。直したあとは、2000〜2027年の 486日すべてが一致しました(2026年10月22日に実行)。

ほかに気をつけたところ

突き合わせで問題は出ませんでしたが、書く段階で気をつけた点です。

  • 振替休日と国民の休日の判定には「本来の祝日」だけを使う。 振替休日や国民の休日を祝日として数えると、休日が1日多くなる年が出うる
  • 法改正と特例。 2019年の即位関連の休日、2020・2021年のオリンピックに伴う海の日・スポーツの日・山の日の移動、天皇誕生日の 12/23 → 2/23
  • 春分の日・秋分の日は予測値。 正式な日付は前年2月の官報で決まる。計算式(1980〜2099年向けの近似式)は公表前の年には予測でしかない
  • new Date('2026-05-06') はタイムゾーンでずれる。 日付だけの ISO 文字列は UTC の0時として解釈されるため、UTC より西のサーバーでは前日になる。new Date(2026, 4, 6) のように数値で作る
new Date('2026-05-06').getDate(); // アメリカ時間のサーバーでは 5
new Date(2026, 4, 6).getDate();   // どこでも 6

まとめ

  • 祝日判定を自作したら、公式の一覧と全件突き合わせる。目で見て「合ってそう」では、今回のような日曜日の例外に気づけない
  • 内閣府のページ上なら、fetch と TextDecoder('shift_jis') だけで突き合わせられる

この記事の祝日判定の全コード(振替休日・国民の休日・特例を含む)と、それを使った「○営業日後」「期間の営業日数」「銀行休業日(12/31〜1/3)」の計算を、Zenn の本の1章にまとめています。振込カナ・和暦・消費税の端数・CSV の文字化けなど、日本の業務データの落とし穴を、公式資料の出典とテストつきで扱った本です(最初の2章は無料)。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?