【ITニュース解説】Building an Ethiopian Calendar in Flutter
2026年10月17日に「Dev.to」が公開したITニュース「Building an Ethiopian Calendar in Flutter」について初心者にもわかりやすく解説しています。
ITニュース概要
Flutterでエチオピア暦アプリを開発。グレゴリオ暦との日付変換エンジンをDartで自作し、ユリウス日を用いた整数演算で正確・高速なオフライン変換を実現。オフラインでの祝日対応、徹底したテスト手法など、複雑なカレンダー機能開発の具体的なノウハウを解説する。
ITニュース解説
このニュース記事は、世界的に主流なグレゴリオ暦とは異なる「エチオピア暦」をFlutterフレームワークで扱うカレンダーアプリを開発した経験について解説している。特に、一般的な日付ライブラリでは対応が難しい特殊なカレンダーのロジックを自作し、さらにアプリを完全にオフラインで動作させるための技術的な工夫が詳細に語られている。システムエンジニアを目指す上で、このようなニッチだが重要な要件に対するアプローチは非常に参考になるだろう。
エチオピア暦は、独特な仕組みを持っている。通常のグレゴリオ暦が12ヶ月なのに対し、エチオピア暦は12ヶ月がそれぞれ30日で構成され、その後に「パグメ」と呼ばれる5日間(閏年には6日間)の短い13番目の月が続く。閏年は、グレゴリオ暦と同様に西暦年が4で割り切れる年とされており、新年のエンクッタタッシュはグレゴリオ暦の9月11日(グレゴリオ暦の閏年の前年は9月12日)にあたる。エチオピア暦はグレゴリオ暦より約7〜8年遅れているという特徴もある。このような固定的な月の長さと閏年のルールが明確であるため、カレンダーの計算ロジックをシンプルに構築できる基盤となっている。複雑な日付ルックアップテーブルを使う必要がなく、ほとんどの計算が簡単な算術演算で済む点が、開発を容易にしている。
このアプリのカレンダーエンジンの核となるのは、「ジュリアン日番号(Julian Day Number: JDN)」という概念だ。異なるカレンダー間を直接変換するのではなく、すべてのカレンダーの日付を一度JDNという共通の数値(ある特定の時点からの経過日数)に変換するというアプローチを採用している。例えば、エチオピア暦の日付をJDNに変換し、そのJDNをグレゴリオ暦の日付に変換するという二段階のプロセスを踏む。この方法の利点は、各変換処理を独立したシンプルな機能として実装でき、それぞれを純粋な関数としてテストできることにある。
エチオピア暦からJDNへの変換は、エチオピア暦の元年1月1日(メスケレム1日)が特定のJDN値に相当することを基準として行われる。まず、指定されたエチオピア暦の年が始まるまでに何日経過しているかを計算する。これには、1年365日という基準と、4年に一度追加される閏日の計算が含まれる。具体的には、「(年-1) × 365 + (年-1) ÷ 4」という式で求められる閏年を含む経過日数を算出する。その後、月と日の経過日数を加算し、エチオピア暦の起点のJDN値を加えることで、最終的なJDNが得られる。月の経過日数は、パグメ月を除いて各月30日であるため、「(月-1) × 30 + (日-1)」という単純な計算で求められる。
JDNからエチオピア暦への逆変換も、同様に整数演算で処理される。JDNからエチオピア暦の起点からの経過日数を引き、その日数を4年周期(365日×4年+1日=1461日)で割ることで、どの4年周期に属するかを特定し、年を割り出す。その後、その年における1年間の何日目かを計算し、それを30日で割って月と日を決定する。グレゴリオ暦とJDNの相互変換についても、既存の確立された整数演算アルゴリズムが利用されている。これらのすべての計算は、浮動小数点数やタイムゾーン処理といった複雑な要素を一切使わず、純粋な整数演算のみで構成されている。これにより、計算結果の正確性が保証され、どのようなモバイルデバイス上でも常に同じ挙動を示し、大量の日付変換が必要な場合でも高速に処理が完了するという、システムの安定性とパフォーマンスが確保されている。
カレンダーエンジンの機能は、「EthiopianCalendar」というシンプルなクラスとして公開されている。このクラスを通じて、エチオピア暦とグレゴリオ暦の相互変換、指定した年の閏年判定、指定した月の日数取得といった機能が、開発者にとって使いやすい形式で提供されている。
ユーザーインターフェース(UI)でカレンダーを表示する際も、このエンジンの恩恵を受ける。エチオピア暦の13ヶ月分の月名リストを用意し、JDNから計算される月の1日の曜日情報と、各月の固定された日数情報を使えば、画面上のカレンダーグリッドを簡単に構築できる。JDNから曜日を計算するシンプルな式「(JDN + 1) % 7」は、UIのレンダリングロジックをさらに簡潔にしている。
このアプリでは、既存の日付変換パッケージを利用せず、あえて自作のカレンダーエンジンを構築している。その理由は、カレンダーアプリの正確性が非常に重要であるため、コードの隅々まで自分自身でテストし、完全に検証できるという点にある。特に、「アンカーテスト」と呼ばれる既知の正しい日付とその変換結果を比較するテストや、「ラウンドトリップテスト」と呼ばれる、ある日付を一方のカレンダーに変換し、それを元のカレンダーに変換し直したときに、元のJDN値と完全に一致するかを数十年分の全日について検証する徹底的なテストが実施された。これにより、既存のパッケージでは見逃されがちな、特定の閏年にのみ発生する「オフバイワン」エラー(1日ずれるバグ)なども確実に発見し、修正できたという。また、外部への依存を排除することで、セキュリティリスクや将来的なアップデートの手間を削減し、60行未満という非常に小さなコード規模は、もしバグが見つかった場合でも、その原因を深く理解し、迅速に修正できるという運用上の大きなメリットをもたらしている。
さらに、このアプリは完全にオフラインで動作するという特徴を持つ。日付の変換だけでなく、エチオピアの祝日や正教会の断食日などの情報も、すべてインターネット接続なしで利用できる。これらの情報は計算で導き出せるものではないため、必要なデータベースをアプリのローカルアセットとして同梱し、アプリ起動時に一度だけ読み込む仕組みを採用している。この設計により、ユーザーは電波の届かない場所や飛行機モードでもすべての機能が瞬時に利用でき、モバイルデータ通信量を消費することもない。このオフライン優先の設計思想は、アプリがバックエンドサーバーを一切持たない「サーバーレス」な構造を実現し、サーバー維持費用やAPIメンテナンスの手間を排除し、ユーザーインターフェース上にもロード中の表示が一切出ないという、非常に快適なユーザー体験を提供している。
カレンダーエンジンとUIは明確に分離されており、UI層はエンジニアが提供する変換結果を画面に表示するだけで、日付の計算ロジック自体は担当しない。このクリーンなアーキテクチャは、コードの保守性を高め、それぞれの層が独立して開発・テストできるメリットがある。
このプロジェクトは、一般的な技術スタックだけでは対応しきれない特殊な要件に対し、独自の正確なカレンダーエンジンをゼロから構築し、さらにアプリを完全にオフラインで動作させるという挑戦的な目標を達成した事例と言える。ジュリアン日番号を介した変換、整数演算の徹底、厳格なアンカーテストとラウンドトリップテストの実施、そしてオフラインデータ戦略は、システムエンジニアとして複雑なドメインロジックを持つアプリケーション開発に取り組む上で、どのような設計思想と技術的アプローチを採用すべきかを示す貴重な示唆を与えている。