はじめに
日時の処理は、システム開発で最も見落としやすい問題の一つです。私たちも実際に、タイムゾーンに関する問題でトラブルを経験しました。本コラムでは、その教訓を共有します。
発生した問題
【症状】
「今日の学習記録」を表示しているはずが、
昨日の記録も混ざって表示される
【原因】
サーバー(UTC)とクライアント(JST)で
日付の境界がずれていた
UTC 00:00 = JST 09:00
→ 朝9時までは「昨日」として扱われていた
タイムゾーンの基本
UTCとJST
UTC(協定世界時):世界標準
JST(日本標準時):UTC + 9時間
例:
UTC 2025-01-15 00:00:00
= JST 2025-01-15 09:00:00
問題が起きやすいケース
- 日付の境界をまたぐ処理
- 「今日」「昨日」の判定
- 日付でのフィルタリング
- 定期実行タスクのスケジュール
解決策
原則:保存はUTC、表示はローカル
【データベース保存時】
UTC形式で保存
→ 2025-01-15T00:00:00Z
【画面表示時】
ユーザーのタイムゾーンに変換
→ 2025年1月15日 09:00(JST)
実装例
// 保存時:UTCで保存
const utc_now = new Date().toISOString();
// → "2025-01-15T00:00:00.000Z"
// 表示時:JSTに変換
function format_jst(utc_string) {
const date = new Date(utc_string);
return date.toLocaleString('ja-JP', {
timeZone: 'Asia/Tokyo'
});
}
「今日」の判定
// JSTベースで「今日」を判定
function get_today_range_jst() {
const now = new Date();
// JSTの今日の開始(00:00 JST = 15:00 UTC前日)
const start = new Date(now.toLocaleString('en-US', {
timeZone: 'Asia/Tokyo'
}));
start.setHours(0, 0, 0, 0);
// JSTの今日の終了
const end = new Date(start);
end.setDate(end.getDate() + 1);
return { start, end };
}
仕様書への記載
## 日時処理規約
### 保存形式
- データベース:UTC(ISO 8601形式)
- 例:2025-01-15T00:00:00Z
### 表示形式
- 画面表示:JST(日本標準時)
- フォーマット:YYYY年MM月DD日 HH:mm
### 日付フィルタリング
- 「今日」はJST基準で判定
- APIパラメータで日付を指定する場合はJSTで受け取る
チェックリスト
- □ 日時はUTCで保存しているか
- □ 表示時にJSTに変換しているか
- □ 日付フィルタの境界は正しいか
- □ テストは日付境界でも行ったか
まとめ
タイムゾーン問題は、仕様書に明記することで防げます。「日時をどう扱うか」を事前に決めておくことが重要です。
次回:「セキュリティを最初から考慮する開発」