【ITニュース解説】Building hldays #2: Modelling holidays from country down to municipality
2026年10月29日に「Dev.to」が公開したITニュース「Building hldays #2: Modelling holidays from country down to municipality」について初心者にもわかりやすく解説しています。
ITニュース概要
祝日管理API「hldays」は、国から市町村まで多様な地域ごとの複雑な祝日を扱うシステム設計を紹介。単純な日付ではなく、地域を階層構造で管理し、祝日を「12月25日」のようなルールで定義する。親から子へ祝日を継承させ、指定された年に具体的な日付を生成することで、地域特有の祝日にも対応できる。
ITニュース解説
システム開発において、日付や時間に関する情報は意外と複雑な課題を抱えている。特に、私たちが日常的に意識する「祝日」は、シンプルに見えてその裏側には地域性、歴史、法律など多岐にわたる要素が絡み合っている。hldaysという祝日管理システムを構築する過程で直面した具体的な問題と、その解決策としてのシステム設計は、現実世界の複雑な情報をデジタルシステムでいかに表現するか、という重要なテーマを示している。
このhldaysプロジェクトは、開発者自身が住む自治体の祝日を忘れがちだったことから始まった。ポルトガルでは国全体の祝日だけでなく、それぞれの自治体固有の祝日が存在するため、これらの情報を効率的に管理する必要があったのだ。
開発者が最初に考えたのは、最も単純なデータベースの形、つまり「日付」「祝日名」「国」という項目を持つテーブルに祝日情報を羅列する「素朴な」モデルだった。しかし、このアプローチはすぐに多くの問題に直面した。
まず、祝日は単なる「日付」ではないという点だ。クリスマスのように「12月25日」と固定された日もあれば、「イースターの2日前」や「11月の第4木曜日」のように、年によって日付が変わる祝日も多い。これらの変動する祝日を、何十年分も手動でデータベースに登録するのは現実的ではなかった。
次に、祝日は必ずしも「国全体」に適用されるわけではないという問題がある。ドイツでは、特定の州だけで祝日となる「公現祭」のように地域差がある。ポルトガルでも、マデイラ諸島独自の祝日や、ブラガ市固有の「聖ヨハネ祭」のような自治体レベルの祝日が存在する。このように、祝日は国、州、地域、そして自治体といった様々なレベルで適用範囲が異なるのだ。
さらに、それぞれの「場所」が持つ階層構造も一様ではない。ポルトガルには地区、2つの自治区、そして308の自治体がある。アメリカには州や準州があり、ドイツにも州がある。これらの複雑な地理的・行政的階層をどのようにシステムで正確に表現するかが大きな課題となった。
これらの課題を解決するために考案されたのが、「管轄区域のツリー構造」と「祝日のルールセット」という二つの主要なアイデアだった。
まず、「管轄区域のツリー構造」は、国、細区分(州や地区)、市町村といった地理的な場所を、親子関係を持つ階層構造として捉える方法である。例えば、「ポルトガル(国)」の下に「ブラガ地区(地区レベル)」があり、さらにその下に「ブラガ市(市町村レベル)」があるといった具合だ。各場所にはユニークなID(国際標準に準拠したものなど)、その場所がどのレベルに属するかを示す情報、そして親となる場所のIDが与えられる。これにより、例えば「PT(ポルトガル)」、「PT-03(ブラガ地区)」、「PT-M-0303(ブラガ市)」のように、場所を明確に識別し、その関係性をシステムが理解できるようになる。この構造は、国によって使われるレベルが異なる場合(例えば、市町村レベルの祝日がない国など)にも柔軟に対応可能だ。また、それぞれの管轄区域には、その地域の週末が何曜日であるかという情報も持たせ、これは「営業日」の計算に不可欠な情報となる。
次に、「祝日の継承」という概念が導入された。これは、特定の場所(例えばブラガ市)の祝日を知りたい場合、その場所自身の祝日だけでなく、その親(ブラガ地区)、さらにその親(ポルトガル全体)の祝日もすべて継承して取得するというものだ。これにより、ブラガ市の祝日を尋ねると、ポルトガル全体の13の祝日と、ブラガ市独自の聖ヨハネ祭が自動的にリストアップされる。取得された各祝日には、「この祝日はポルトガル全体のものか、それともブラガ市固有のものか」を示す情報が付与されるため、どこから継承された祝日なのかが一目でわかるようになっている。また、特定の場所が親から継承される祝日を例外的に「採用しない」ケース(例えば、アメリカの一部の州が連邦祝日をスキップする場合)にも対応できるよう、「除外リスト」の仕組みも用意されている。この継承メカニズムは、システムにおいて共通の情報を上位から下位へ効率的に伝達しつつ、下位での個別の差異も許容する設計の良い例となっている。
そして最も重要な点が、「祝日を日付ではなくルールとして格納する」という設計判断だ。先述の通り、祝日は毎年同じ日付ではないものが多い。そこで、hldaysシステムでは、具体的な「2026年12月25日」という日付ではなく、「12月25日」や「イースターから60日後」、「5月の最終月曜日」といった「祝日の計算ルール」をデータとして保持する。これらのルールは、固定日、イースターからのオフセット、月のN番目の曜日、特定の日付以前の特定の曜日、あるいは政府が毎年個別に定めるような明示的な日付リスト、さらには非グレゴリオ暦に基づく日付まで、様々な形式で定義できるようになっている。ユーザーが特定の年(2016年から2099年まで)の祝日を問い合わせると、システムはこれらのルールを基に、その年の具体的な祝日の日付をその場で計算して返す仕組みだ。これにより、データベースに何十年分もの日付データを手動で入力したり、法律が変更されて祝日が追加・削除された際に大量のデータを修正したりする手間がなくなる。祝日の有効期間を示す「valid_from」と「valid_to」というフィールドも用意されており、例えばブラジルの祝日のように、2024年から全国的な祝日となったものや、過去に一時的に停止されたポルトガルの祝日など、時間の経過とともに変化する祝日にも柔軟に対応できる。
さらに、祝日にはその性質を示す「タイプ」と、情報の信頼性を示す「ステータス」というフィールドも追加されている。「タイプ」は、法律で定められた休日(public)、自治体固有の休日(local)、合意や政府決定による任意の休日(optional)といった種類を区別し、APIの利用者がどのような祝日を知りたいかに応じてフィルタリングできるようにしている。「ステータス」は、その祝日情報が公式な情報源(政府のウェブサイトなど)によって確認済み(verified)であるか、まだ未確認(unverified)であるかを示している。特に、URLや確認日、引用元まで含めて記録されており、データの信頼性を確保するための強いこだわりが見られる。
システムは、ユーザーが「Lisbon」や「Braga」といった名前で管轄区域を検索できるようにもなっている。しかし、「Braga」が地区名と市名両方に存在するように、名前だけでは一意に特定できない場合がある。このため、システムは最も具体的なレベルの場所を優先して返したり、国名を指定することで曖昧さを解消したり、さらには英語名などのエイリアスにも対応したりと、ユーザーの利便性を高めるための工夫が凝らされている。祝日の名前自体も、ポルトガル語と英語のように多言語で保存され、国際的な利用を想定した設計となっている。
hldaysのシステム設計は、一見するとシンプルな「祝日」という情報がいかに複雑な側面を持ち、それをどう効率的かつ正確に、そして将来にわたって保守可能な形でシステムに落とし込むかという、現実の課題解決プロセスを鮮やかに示している。このシステムから得られた教訓、すなわち「祝日よりも場所を先にモデル化すること」「日付ではなくルールを保存し、日付を生成すること」「値の出所を常に明示すること」は、複雑な要件を分解し、適切なデータモデルとロジックを設計する上での普遍的な原則として、その価値を大きく示している。