FullCalendarで行政カレンダーを作る9時間のズレとLGWANの壁
自治体グループウェアにカレンダーを載せる。FullCalendarを使ってみると、9時間ずれる時刻、週の始まり、日本語化、フェリー、特別職、そして閉域網LGWANという壁が次々に現れた。その記録。
「ただのカレンダー」は無かった
自治体グループウェアに予定表を載せることになった。カレンダーUIの定番、FullCalendar を採用する。月表示・週表示・ドラッグでの予定移動——見た目はすぐ整った。だが、行政のカレンダーは「ただのカレンダー」では済まなかった。時刻の扱い、現場の慣習、地域の事情、そして自治体特有のネットワーク制約が、次から次へと顔を出した。順に書いていく。
9時間、ずれる
最初にぶつかったのが時刻だ。とはいえ、すべての予定が一律に9時間ずれるわけではなかった。厄介なのは、日をまたぐ予定の「終わりの時刻」でだけ症状が出た点だ。
具体例で書く。
- 7月1日 15:00 〜 7月2日 8:30 の予定 → 7月1日にしか表示されない(2日に届かない)
- 7月1日 15:00 〜 7月2日 9:00 の予定 → 7月1日から7月2日まで、ちゃんと帯で表示される
同じ「翌日にまたぐ予定」なのに、終了時刻が朝9:00より前か後かで挙動が割れる。背景にあるのは、日本時間(JST、UTC+9)のはずの日時が、どこかで一度UTCとして解釈されていたことだ。終了が9時間巻き戻ると、7/2 8:30 は 7/1 の深夜側へ落ちて「2日に届かない」ことになり、7/2 9:00 はぎりぎり2日の側に残る——ちょうど朝9:00が境目になっていた。カレンダーというドメインで最も事故が多いのが、この日時とタイムゾーンの境界である。

現行版は少し古い世代の FullCalendar で、内部で moment.js に依存して時刻を扱っていた。この世代のタイムゾーンの取り回しでは原因を一点で断つのが難しく、小手先の変換を挟むほど別の画面で新しいズレが生まれる。そこで現場には、「2日以上にまたがる予定は、終了を9:00以降にしてください」という運用でしのいでもらっている。設計で直しきれない間は、使い方でかわす——現場を止めないための、暫定の知恵だ。
そして根本解決は、次期バージョン環境で FullCalendar を新しいメジャーバージョンへ更新して果たした。新しい世代は moment 依存を脱し、時刻の解釈が「ローカル時間を素直に扱う」方向に刷新されている。バージョンアップ後は、終了が8:30だろうと日をまたぐ予定が正しく帯で出る。完全に治っている。ライブラリの「世代」そのものが、この問題の解だった。
教訓は身も蓋もない。日時は、必ずタイムゾーンとセットで設計する。 文字列がUTCなのかローカルなのか、どの層で変換されるのかを曖昧にしたまま重ねると、9時間はいつでも戻ってくる。
週の始まりは、日曜か月曜か
次は些細に見えて、実は好みが割れる問題。カレンダーの左端は日曜始まりか、月曜始まりか。役所の慣習でも人によっても意見が違う。FullCalendar には firstDay という設定があるので、これを個人ごとに設定できるようにした。全体でひとつに決めず、使う人が選ぶ。小さな自由だが、毎日見るものだから効く。
日本語化は、ひとつの関数に閉じ込める
日付入力(datePicker)の曜日名・月名などの日本語表示は、システムのあらゆる画面に登場する。これを各画面でその都度書いていたら、表記も挙動もばらつく。そこで日付入力の日本語化をひとつの共通関数に集約した。呼ぶ側は種別を渡すだけでよい。以前別稿で書いた「唯一の基準を作る」を、地味なところで実践した形だ。
地域の事情が、機能になる
面白かったのがフェリーだ。離島を抱える自治体では、フェリーの運航予定が生活と行政の背骨になる。会議も出張も、船が出るかどうかで決まる。そこでカレンダーにフェリーの運航予定とアイコンを組み込み、予定表の上で船の便が一目で分かるようにした。汎用のカレンダーライブラリに、その地域でしか要らない機能が乗る——NGWらしい瞬間である。

このほか、毎週・毎月といった様々な繰り返し設定、予定に参加者を紐づけるメンバー登録なども載せた。どれも「あると便利」ではなく、現場が実際に回すために要るものだった。
特別職の予定は、権限で見せる
特別職(幹部)の予定もカレンダーへ連携表示する。ただし幹部の動静は機微なので、管理職に限定して見せる。ここは以前のプライバシー保護の記事と同じ発想で、「見せる/見せない」を権限で判定する。カレンダーもまた、可視性の設計から逃れられない。
LGWANという壁
最後に、いちばん大きな壁。「いっそGoogleカレンダーやOutlookと同期できれば」と誰もが思う。FullCalendar にも Google Calendar 連携の仕組みは用意されている。だが、それは使えない。
多くの自治体の内部ネットワークは LGWAN(総合行政ネットワーク) という閉域網にある。セキュリティのためインターネットから隔離されており、外部のクラウドサービスへ自由に出ていけない。つまり、クラウドカレンダーとの同期は機能の優劣以前に、原理的に不可能なのだ。だからこのカレンダーは、外に頼らず自己完結で作るしかない。制約が、設計の前提を決める。
AIとの協働作業での学び
カレンダーは、単純そうに見えていちばん多くの難所を抱えるドメインだ。時刻とタイムゾーン、個人ごとの好み、日本語化、地域固有の事情、権限による可視性、そして閉域網という制約——UIの裏に、これだけのものが詰まっている。
「ただのカレンダーでしょう」と言われるたびに、9時間のズレとフェリーとLGWANを思い出す。NGWの難しさは、こういう「当たり前に見えるもの」の内側にこそ宿っている。