エポックタイムスタンプ解説:Unix時間の仕組みとその問題点
エポックタイムスタンプ(Unix時間またはPOSIX時間とも呼ばれる)は、1970年1月1日 00:00:00 UTCから経過した秒数(うるう秒を除く)です。これは、タイムゾーンやカレンダーシステムに依存しない、特定の瞬間を表すシンプルな整数です。このシンプルさから、コンピュータが時間情報を交換する標準的な方法となっていますが、すべての開発者が理解すべき既知の制限や落とし穴もあります。
Unix時間の仕組み
Unix時間はエポックから前方にカウントされます。1日は86,400秒(24 × 60 × 60)です。タイムスタンプは、タイムゾーン、サマータイム、うるう年に関係なく、1秒ごとに正確に1ずつ増加します。
Timestamp 0 → 1970-01-01 00:00:00 UTC
Timestamp 86400 → 1970-01-02 00:00:00 UTC
Timestamp 1000000 → 1970-01-12 13:46:40 UTC
Timestamp 1782000000 → 2026-06-17 00:00:00 UTC
// JavaScript — 現在のUnixタイムスタンプを取得
const nowInSeconds = Math.floor(Date.now() / 1000);
console.log(nowInSeconds);
// タイムスタンプを日付に変換
const date = new Date(nowInSeconds * 1000);
console.log(date.toISOString());
// PHP — 現在のUnixタイムスタンプを取得
echo time(); // エポックからの秒数
echo microtime(true); // マイクロ秒精度の秒数
// タイムスタンプを日付に変換
echo date('Y-m-d H:i:s', 1782000000);
秒 vs ミリ秒:バグの一般的な原因
タイムスタンプ関連のバグで最も多いのは、秒とミリ秒を混同することです。JavaScriptの Date.now() はミリ秒を返しますが、PHPの time() は秒を返します。多くのデータベースは秒でタイムスタンプを保存し、多くのAPIはミリ秒を使用します。
| システム | 単位 | サンプル値 | 日付 |
|---|---|---|---|
| Unix / POSIX | 秒 | 1782000000 |
2026-06-17 |
JavaScript Date.now() |
ミリ秒 | 1782000000000 |
2026-06-17 |
Java System.currentTimeMillis() |
ミリ秒 | 1782000000000 |
2026-06-17 |
PHP time() |
秒 | 1782000000 |
2026-06-17 |
Python time.time() |
秒(浮動小数点) | 1782000000.123 |
2026-06-17 |
// ❌ 間違い — ミリ秒として扱っている
const timestamp = 1782000000; // これは秒単位
const wrongDate = new Date(timestamp); // ミリ秒として解釈
console.log(wrongDate.toISOString()); // 1970-01-21 — 完全に間違い
// ✅ 正しい — 1000を掛ける
const correctDate = new Date(timestamp * 1000);
console.log(correctDate.toISOString()); // 2026-06-17
import time
from datetime import datetime
# ❌ 間違い — ミリ秒の除算を忘れている
millis = 1782000000000
wrong = datetime.fromtimestamp(millis) # ValueError: year out of range
# ✅ 正しい
correct = datetime.fromtimestamp(millis / 1000)
print(correct) # 2026-06-17 00:00:00
2038年問題
Unix時間は符号付き32ビット整数を使用しており、最大値は2,147,483,647です。2038年1月19日 03:14:07 UTCに、タイムスタンプはこの限界に達します。1秒後、32ビット符号付き整数は−2,147,483,648にラップされ、これは1901年12月13日に相当します。
2,147,483,647 → 2038-01-19 03:14:07 UTC(32ビット符号付きの最大値)
2,147,483,648 → 負の値にラップ(アンダーフロー)
Y2038の影響を受ける可能性があるシステム:
- 組み込みシステム(ルーター、IoTデバイス、車載ファームウェア)
- タイムスタンプを
INT(10)で保存しているレガシーデータベース - 32ビットアーキテクチャの古いLinuxカーネル
- 32ビットタイムスタンプを使用するファイルシステム
- 32ビットビルドの古いバージョンのPHP
システムがY2038対応か確認する方法:
# Linux — time_tが64ビットか確認
getconf LONG_BIT
# 64 → 安全
# 32 → カーネルとlibcのバージョンを確認
# PHP — 整数サイズを確認
php -r 'echo PHP_INT_SIZE;'
# 8 → 安全(64ビット)
# 4 → 脆弱(32ビット)
64ビット time_t を搭載した最新システムは、約2920億年先までのタイムスタンプを表現できるため、Y2038は問題になりません。ほとんどの本番サーバーは既に64ビットOSで動作していますが、組み込みシステムやレガシーシステムは引き続きリスクがあります。
うるう秒:隠れた複雑さ
Unix時間はうるう秒を無視します。定義上、各日は正確に86,400秒です。しかし、天文時間(UT1)は地球の自転に合わせるために、時折追加の1秒(うるう秒)を必要とします。うるう秒が発生すると、Unix時間は同じ秒を繰り返します:
2016-12-31 23:59:59 UTC
2016-12-31 23:59:60 UTC ← うるう秒(Unix時間では表現不可)
2017-01-01 00:00:00 UTC
ほとんどのアプリケーションは、うるう秒が予測不可能に発生し(通常1〜3年に1回)、その処理に大きな複雑さが加わるため、うるう秒を完全に無視します。金融取引プラットフォームや天文台など、正確な計時が必要なシステムは、Unix時間の代わりにTAI(国際原子時)やGPS時間を使用します。
よくある落とし穴
落とし穴1:誤った単位の使用
// APIが秒でタイムスタンプを返す
const apiTimestamp = 1782000000;
// ❌ 間違い — new Date()はミリ秒を期待
const date = new Date(apiTimestamp);
// ✅ 正しい
const date = new Date(apiTimestamp * 1000);
落とし穴2:MySQLでINT(10)として保存
-- ❌ 間違い — INT(10)は21億(2038年)でオーバーフロー
CREATE TABLE events (
created_at INT(10) NOT NULL
);
-- ✅ 正しい — BIGINTまたはTIMESTAMPを使用
CREATE TABLE events (
created_at BIGINT NOT NULL, -- 64ビット、安全
created_at2 TIMESTAMP NOT NULL -- MySQLが変換を処理
);
落とし穴3:ローカル時刻がデフォルトと想定
// ❌ 間違い — date()はサーバーのデフォルトタイムゾーンを使用
echo date('Y-m-d H:i:s', $timestamp);
// ✅ 正しい — 明示的にUTCを指定
echo gmdate('Y-m-d H:i:s', $timestamp);
echo date('Y-m-d H:i:s', $timestamp); // デフォルトTZがUTCに設定されている場合
落とし穴4:JavaScriptでの整数オーバーフロー
JavaScriptの数値は64ビット浮動小数点ですが、ビット演算では32ビット符号付き整数として扱われます。これにより、最新のブラウザでも予期しないY2038類似のバグが発生する可能性があります。
// JavaScriptのビット演算は32ビットとして扱われる
const timestamp = 2500000000; // 32ビット符号付き最大値を超える
const shifted = timestamp << 1; // ❌ オーバーフロー!
console.log(shifted); // -1794967296(ラップ)
エポックコンバーターツール
Help2Codeのエポック/Unixタイムスタンプコンバーターは、秒とミリ秒でのリアルタイム現在タイムスタンプ表示、エポック値と読み取り可能な日付の双方向変換、ローカルタイムゾーンとUTCの両方をサポートしています。タイムスタンプの問題のデバッグ、テスト用タイムスタンプの生成、APIレスポンスの検証に使用してください。タイムゾーンコンバーターも、エポックタイムスタンプが異なるタイムゾーンにどのようにマッピングされるかを確認するのに便利です。
結論
エポックタイムスタンプは、時間の瞬間を表すシンプルで普遍的な方法ですが、いくつかの重要な注意点があります:常に秒とミリ秒のどちらを扱っているかを確認し、Y2038問題を避けるために64ビットストレージを使用し、デフォルトのタイムゾーンが意図したものと一致すると想定しないでください。クイック変換にはエポックコンバーターツールを使用し、本番コードでタイムスタンプを扱う際は上記のガイドラインを念頭に置いてください。