NocoBaseコミュニティで繰り返し報告されるバグに、「すべての時刻が8時間ずれている」「日付が前日になる」というものがあります。特に中国語フォーラムでよく見られます。中国はUTC+8なので、ずれも8時間です。私はUTC+9でインスタンスを運用していますが、予想通り9時間のずれが発生しました。オフセットが何であれ、その分だけずれます。
このパターンは、偶然の破損ではなく、明確な仕組みであることを強く示唆しています。そこで、NocoBase 2.xをPostgreSQLとMySQLの両方で実際に構築し、実際に保存される値と再解釈の方法を計測し、謎に具体的な答えを導き出しました。
テスト環境:NocoBase 2.0.51および2.1.23(公式Dockerイメージ)× PostgreSQL 16およびMySQL 8.4。すべてのデータはREST APIを通じて書き込み・読み込みを行い、サーバーのタイムゾーンはコンテナの
TZ環境変数で制御しました。ブラウザ側のレンダリングは意図的に無視し、ここではサーバーが何を保存し、どのように解釈するかに焦点を当てています。
背景:2.xには4種類の日時フィールド型がある
NocoBase 2.xのコレクションには、4種類の日時関連フィールド型があります(公式リスト — ただし、タイプごとの詳細ページの多くに「To be added」と記載されているため、実際に計測しました):
| 型 | 用途 |
|---|---|
| Datetime(タイムゾーンあり) | 絶対的な瞬間 — イベント開始時刻、ログなど |
| Datetime(タイムゾーンなし) | そのまま保存したい時刻(壁時計時間) |
| Date only | 誕生日、締切日、記念日など |
| Unix timestamp | システム連携 |
計測1:各型が実際に保存するもの
「2026-07-12 09:00」をxlsxでインポートし、各データベースの生の値を確認しました(2.0.51と2.1.23で同一):
| フィールド型 | PostgreSQL | MySQL |
|---|---|---|
| Datetime(タイムゾーンあり) |
timestamptz → 2026-07-12 09:00:00+09(オフセットを含む絶対的な瞬間) |
DATETIME → 2026-07-12 09:00:00(壁時計時間のみ — オフセット情報なし) |
| Datetime(タイムゾーンなし) |
timestamp → 09:00:00 |
DATETIME → 09:00:00 |
| Date only |
date → 2026-07-12 |
date → 2026-07-12 |
最初の行がすべてを物語っています。同じフィールド型「Datetime(タイムゾーンあり)」でも、PostgreSQLでは絶対的な瞬間として保存され、MySQLでは裸の壁時計時間として保存されます。MySQLのDATETIMEにはオフセットを格納する場所がありません。次の実験のためにこの点を覚えておいてください。
計測2:サーバーのTZを変更すると保存されたデータの意味が変わる(MySQL)
MySQL環境で、サーバーをTZ=UTCで動作させながら「2026-07-12 09:00」を書き込みました。その後、アプリコンテナをTZ=Asia/Tokyoに変更して再起動しました。他は何も変更していません。
# MySQLの生の値(1バイトも変わっていない)
dt_tz: 2026-07-12 09:00:00
# APIが返す値
TZ=UTCの場合 → "2026-07-12T09:00:00.000Z" (= UTC+9では18:00)
TZ=Asia/Tokyoの場合 → "2026-07-12T00:00:00.000Z" (= UTC+9では09:00)
Enter fullscreen mode Exit fullscreen mode
ディスク上のデータはバイト単位で同一ですが、絶対的な瞬間としての意味が9時間ずれる。 MySQLのDATETIMEは「この09:00がどのタイムゾーンのものか」を記録しないため、NocoBaseは読み書きのたびにサーバーのTZで解釈する必要があります。後からTZを変更すると、データベースに保存されたすべての日時が一斉に意味を変えてしまうのです。
この仕組みが、「8時間ずれ」という繰り返しの報告のほとんどを説明します。インスタンスがTZ未設定(= UTC)で開始され、後でローカル時間に設定された場合や、ステージングと本番でTZが異なる場合などです。データは損なわれておらず、解釈が変わっただけです。
ではPostgreSQLではどうでしょうか。同じ実験を行いましたが、値は動きませんでした。 timestamptzにオフセットが保存されているため、再解釈の余地がありません。
ここから2つのルールが導き出されます:
-
初日にサーバーの
TZを選び、決して変更しない — 特にMySQLの場合。composeファイルで明示的に固定し、開発・ステージング・本番などすべての環境で同一に保つ。 - データベースを選べるなら、PostgreSQLはこの種の事故に対して構造的に免疫がある。
別件:インポート日付バグ(実在し、修正済み)
日付のずれがすべてこの仕組みによるものとは限りません。2.x時代に実際に存在したバグもありました。v2.0.44〜2.0.51では、データベース・アプリ・サーバーのタイムゾーンがすべて一致していても、CSV/Excelインポートで日付が1日前に保存されることがありました。これは欠陥として確認され、2026年5月中旬に修正されました(フォーラムスレッド t/12426、t/12494)。
参考までに、2.0.51でAPI経由のxlsx/CSVインポートは再現できませんでした。両方のデータベースで正しく保存されました。報告はUI経由のパスが関与していた可能性があり、他のルートや環境要因が影響したと考えられます。いずれにせよ、現在のバージョンでは修正されています。
実践的な教訓:日付がずれた場合、「これはこの仕組みによるものか?」と「これは自分のバージョンで既知のバグか?」を区別することです。計測1と2を理解すれば前者の問いに答えられ、フォーラム検索(中国語カテゴリを含む — 最も活発です)で後者の問いに答えられます。
チェックリスト
- フィールド型を意味に合わせる。 誕生日や締切日は「Date only」に。絶対的な瞬間は「Datetime(タイムゾーンあり)」に。「Datetime(タイムゾーンあり)」を日付のみのデータに使うと、日付が1日ずれて表示される典型的な原因になります。
-
初日にcomposeファイルでサーバーの
TZを固定し、以後触らない(特にMySQL)。UTCでもローカルゾーンでも構いません。どちらかを選んで一貫して使用してください。 - インポート後は1件のレコードを開いて日時を確認する。 これらのずれはすべての行に一様に影響します。1件のレコードで全体がわかります。
- 何かずれている場合:バージョン確認後、フォーラムを検索する — 特に中国語カテゴリで、実際の報告のほとんどがそこで見つかります。
まとめ
- NocoBase 2.xの「Datetime(タイムゾーンあり)」は、PostgreSQLでは絶対的な瞬間ですが、MySQLでは壁時計時間 +
TZによる解釈です(実測)。 - そのため、後からサーバーの
TZを変更すると、MySQLでは保存されたすべての日時の意味がずれてしまいます。これが「8時間ずれ」(または9時間、またはオフセットに応じたずれ)の繰り返しの原因です。 - インポート時の日付ずれバグは実在しましたが、修正済みです。仕組みと既知のバグを区別することで、診断が迅速になります。
(2.0.51 / 2.1.23 × PostgreSQL 16 / MySQL 8.4で計測。将来的なバージョンで動作が変わる可能性があります。)
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.