書類が明日に飛んだ理由——JSTとUTCの二重解釈が壊すデータ
同じ日時列をJST壁時計とUTCで読み書きした結果、登録日が翌日にずれ、深夜取引や明細の孤児化が発生した実例と是正の要点を解説します。
書類が明日に飛んだ。
担当者が業務時間内に登録したはずの書類が、システム上では翌日の日付で記録されていました。原因を追っていくと、それだけでは終わりませんでした。深夜23時台にまとまって発生しているはずのない取引記録、そして販売明細が本来紐づくべきグループから全件外れて孤立している状態——一見無関係に見えるこの三つの不具合は、根っこを同じくする一つの問題から生まれていました。
登録した書類が「明日」に消える
最初に報告が上がったのは、書類管理画面での違和感でした。担当者が日中に登録した書類が、一覧では翌日の日付で表示される。最初は入力ミスや画面のキャッシュを疑いましたが、何度試しても同じ現象が再現します。
さらに調べると、取引記録の一部が23時台に集中して発生しているように見える箇所が見つかりました。実際の業務がその時間に動いているはずはなく、明らかにおかしい。加えて、販売明細を集計するバッチ処理では、本来紐づくはずのグループにまったく紐づかず、対象の明細が丸ごと外れて孤立するという症状も確認されました。
表示のズレ、記録時刻の異常、集計の失敗——症状としては別々の場所で起きているように見えますが、これらはすべて同じ原因から発生していました。
9時間のずれが日付をまたぐ仕組み
原因は、データベースに保存されている同じ日時列を、画面ごとに異なる基準で解釈していたことにありました。ある画面では保存された値を日本時間(JST)の壁時計時刻としてそのまま表示し、別の処理では同じ値をUTC(協定世界時)として扱って計算していたのです。
JSTはUTCより9時間進んでいます。つまり、UTCで「今日の15時」はJSTでは「今日の深夜0時」を過ぎて「翌日の未明」に相当します。この9時間のズレが問題になるのは、常にではありません。日中の時間帯であれば9時間のズレがあっても日付そのものは変わらないことが多く、症状が出にくいのです。ところが、日付境界に近い時間帯——JSTで夕方から深夜にかけて登録されたデータになると、UTCとして解釈した瞬間に日付がまるごと変わってしまいます。
書類の登録日が翌日にずれていたのは、登録処理のどこかでUTCとして保存すべき値をJSTの壁時計時刻として扱い、そのズレた値がそのまま「登録日」として確定してしまっていたためです。取引記録が23時台に集中して見えたのも同じ構造で、実際にはUTCで日中に発生した取引が、JST基準の表示ロジックを通した際に深夜帯へ押し出されていた、というのが実態でした。
表示のズレも記録時刻の異常も、原因は「同じ値を、場所によって違う時間の基準で読んでいた」という一点に集約されます。
なぜ明細が100%孤児になったのか
もっとも深刻だったのは、販売明細の集計処理でした。ここでは日時由来の値がグルーピングのキーの一部として使われており、9時間のズレがそのままキー照合の失敗に直結していました。
集計処理は、明細のタイムスタンプから日付部分を切り出し、その日付をキーとして親となるグループのレコードと突き合わせる仕組みでした。ところが、明細側のタイムスタンプはUTCで保存されている一方、グループ側の日付はJST基準で確定していました。この状態で日付部分だけを取り出すと、日付境界をまたぐケースでは双方の日付が一致しなくなります。
厄介なのは、これが一部のレコードだけの問題ではなく、条件がそろえば構造的に全件へ及ぶという点です。日付というキーは「その日一日」という粒度でしか一致を判定できないため、9時間のズレによって片方の基準が日付をまたいでしまうと、その日に登録された明細はことごとく照合に失敗します。結果として、対象範囲の明細が丸ごとどのグループにも紐づかない「孤児」状態になっていました。時刻のズレが数分・数秒であれば紛れて見逃されたかもしれませんが、9時間という大きさが日付という粗い粒度のキーと組み合わさったことで、症状が一気に全件へ広がったのです。
調査と是正で実際にやったこと
是正の対応は、2026年8月上旬に書類登録まわりの4ファイルを修正する形で実施されました。変更規模は約95行の追加と3行の削除で、登録日を確定する処理の時刻基準を統一し、保存時と表示時で解釈がずれないように手直ししています。あわせて、同月4日の定例会では、今回の調査結果と是正内容を議事録に反映し、関係者間で経緯と対応方針を共有しています。
修正の要点は、特殊な仕組みを新設したわけではなく、「保存されている値がどちらの基準の時刻なのか」という前提を、登録処理・表示処理・集計処理のあいだで一致させたことにあります。裏を返せば、それまではこの前提がコード上で明文化されておらず、実装者の理解や画面ごとの実装方針に依存していたということです。時刻の扱いが暗黙のルールに留まっている限り、同種の不一致は形を変えて再発する可能性が残ります。
自社DBで同じ地雷を踏まないために
今回の問題が示しているのは、時刻のズレは表示上の些末な違いではなく、日付をキーにした照合や集計を静かに破綻させる実害だという点です。特に日付境界をまたぐ深夜帯の処理や、日時から日付だけを切り出してキーにする集計ロジックは、時刻基準の不一致が発覚しにくいまま蓄積しやすい領域です。
自社のデータベースを点検する際は、次の観点を確認しておくと安心です。
- 日時列をデータベースに保存する際の基準(UTCかローカル時刻か)が、テーブルやシステム全体で統一されているか
- 画面表示や集計処理のたびに、その基準から変換するタイミングと方法が一貫しているか
- 日付をキーにした照合・グルーピングが、異なる時刻基準の値をまたいで行われていないか
理想的には、保存は一貫してUTCで行い、ユーザーに見せる表示の直前だけでローカル時刻に変換する、という一本化した設計に寄せておくことです。基準を一つに決め、変換ポイントを絞り込んでおけば、深夜帯の取引や月末月初の集計処理でも、日付が静かに一日ずれて業務データが壊れるという事態を避けられます。時刻の扱いは地味な設計判断に見えて、実際には業務データの信頼性を左右する土台にあたる部分です。