Hugo の date は UTC で判定される。固定時刻の規約を作ろうとして2回失敗した

新しい記事をデプロイしたのに、サイトに出てこなかった。 この記事では、HugoのdateフィールドがUTCで判定されることによるCI/CDパイプラインでの問題とその解決策を解説する。CI は全ジョブ success。Hugo のビルドも正常終了。しかし記事が存在しない。

Hugo の date 判定

Hugo は --buildFuture フラグなしでビルドすると、date フィールドがビルド実行時刻より未来の記事を除外する。 注意: この動作はHugoのデフォルト設定です。静的サイトジェネレーターとして、未来の記事を「下書き」として扱う設計になっています。draft でなくても関係ない。日時が未来であれば出力されない。

判定はUTCで行われる。フロントマターにJSTで書いても、HugoはUTCに換算してから比較する。 例えば、GitLab CIやGitHub Actionsなどの多くのCI環境はUTCで動作するため、この時差の問題が発生しやすくなります。

date: 2026-02-27T09:00:00+09:00  # = UTC 00:00:00

この記事は日本時間2月27日午前9時だが、UTCでは2月27日の0時ちょうどだ。

1回目の失敗

CIパイプラインが実行されたのは2026-02-26T23:38Zだった。記事のUTC日時は2026-02-27T00:00Z。ビルド時刻より22分だけ未来だったため、除外された。

ここで「安全な固定時刻を設定すればいい」と考えた。T09:00:00+09:00はUTC 00:00:00になる。これをT12:00:00+09:00(= UTC 03:00:00)に変えれば、深夜のCIでも安全なはずだ。

2回目の失敗

T12:00:00+09:00 = UTC 03:00:00 に変更してデプロイした。今度こそ大丈夫だと思ったが、また失敗した。

CIが実行されたのは2026-02-27T02:45Z。記事のUTC日時は2026-02-27T03:00Z。また15分だけ未来だった。

パイプライン実行: 02:45 UTC
記事の date:      03:00 UTC  ← まだ未来

「安全な時刻」にしようとするたびに、CI がその時刻より前に走った。

何がおかしかったか

固定時刻の規約を作ろうとしていること自体が間違いだったのだ。

CIはMRを作成した直後に走る。記事を書いた時刻から数分後だ。 一般的なCI/CDパイプラインの流れ:

  1. コード変更をpush/MR作成
  2. CI環境でコンテナ起動(30秒〜2分)
  3. 依存関係インストール(1〜3分)
  4. Hugoビルド実行(数秒〜1分)記事のdateにその時点の現在時刻を入れれば、CIが走るときには必ず過去になっている。
# 記事を書いた時刻をそのまま入れる
date: 2026-02-27T11:55:00+09:00

CIが数秒で完了するわけではない。コンテナ起動・依存関係インストール・ビルドで最低数分かかる。現在時刻を入れた時点で、すでにCIより数分先行している。

「安全な固定時刻」を探す必要はなかった。むしろ、記事を書いた時点の現在時刻を使用することが最も確実な解決策だ。date は記録であり、Hugo の future-date 判定を回避するための変数ではない。

--buildFuture という選択肢

ビルドコマンドに--buildFutureを追加すれば未来日時の記事も出力される。

# 通常のビルド
hugo

# 未来記事も含めてビルド
hugo --buildFuture
```予約投稿のように「この日時から公開したい」という要件があれば有効だ。

現在時刻を入れるだけで十分だった。