2038年問題と64bit化の対応
公開: 2026-06-16・対象: SRE・組み込み・DB管理者
2038年1月19日03時14分07秒(UTC)、32bit符号付き整数で秒数を保持するシステムでUNIX時間がオーバーフローして1901年12月13日に巻き戻る『2038年問題(Y2038)』。残り12年。現代の主要OS・言語は64bit化済みですが、組み込み機器・レガシーDB・古いファイルフォーマットには確実に残っています。
なぜ2038年1月19日なのか
32bit符号付き整数(int32_t)が表現できる最大値は 2,147,483,647(2の31乗 - 1)。これをUNIXエポック(1970-01-01 00:00:00 UTC)から秒数として加算すると:
# UNIX秒 2,147,483,647 を日時に変換 date -u -d @2147483647 -Iseconds # → 2038-01-19T03:14:07+00:00 # +1秒すると32bit signed intはオーバーフロー # → -2,147,483,648(1901-12-13T20:45:52 UTC)
UNIX時間を扱う型 time_t がC言語で32bit signedとして定義されていた歴史的経緯から、この問題は『2000年問題(Y2K)』に次ぐ規模で語られてきました。
現代の主要OS・言語は対応済み
- Linuxカーネル:5.6(2020年4月)で32bitアーキ含めて全API y2038-safe化。64bit time_tに統一。
- glibc:2.32(2020年8月)で32bitプラットフォーム向けに
_TIME_BITS=64切り替え可能。 - NetBSD / OpenBSD / FreeBSD:いずれも2010年代前半に64bit time_t化完了。
- macOS / Windows:64bit OSは元から64bit time_t。
- Java:
long(64bit)で保持するため影響なし。 - JavaScript:DateはIEEE 754倍精度浮動小数(53bit整数精度)。±約285,616年まで安全。
- Python:内部実装は64bit。
datetime.MAXは9999年。 - Go:
time.Timeは64bit基盤、影響なし。
つまり2020年以降にビルドされたLinuxサーバー・最近5年のスマートフォン・主要クラウドはそのままで2038年を越えられます。
今も残るリスクポイント
- 古い組み込み機器:産業機器・医療機器・自動車・スマートメーター・ATMなど、ファームウェア更新が事実上不可能な機器。2038年に向けて入れ替え計画が必要。
- MySQLのTIMESTAMP型:内部表現が32bit UNIX秒。2038-01-19以降の日時を保存できない。
DATETIME(64bit内部)またはBIGINTへの移行が必要。 - PostgreSQLのtimestamp:内部はマイクロ秒精度の64bit整数で2038年問題なし。
- レガシーアプリのINT(4)カラム:UNIX秒を32bit INTで保存しているDBスキーマ。
BIGINTに変更が必要。 - 古いファイルフォーマット:ZIPの古い拡張、tar(ustar)の32bit mtime、ext2/ext3のi_atime/i_mtime/i_ctime。ext4は2038年問題対応済み。
- 金融系の長期契約:30年住宅ローンの管理システムは、すでに2038年を扱う場面に到達しているはず。点検済みのはずですが要確認。
- 32bit版iOS(旧iPhone 5以前)・32bit Android:すでにサポート外ですが、現役のIoT機器に同等のARMv7 32bitが残ります。
MySQL TIMESTAMP → BIGINT 移行手順
MySQLのTIMESTAMPカラムを64bit対応のBIGINTまたはDATETIMEに移行する流れ:
-- 既存テーブルを確認 SHOW CREATE TABLE orders; -- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -- ① 移行先カラムを追加 ALTER TABLE orders ADD COLUMN created_at_v2 BIGINT UNSIGNED NULL; -- ② 既存値をコピー(UNIX秒へ) UPDATE orders SET created_at_v2 = UNIX_TIMESTAMP(created_at); -- ③ アプリ側を両書きに(writeは新旧両方、readは新カラム優先) -- ④ 旧カラム削除&リネーム ALTER TABLE orders DROP COLUMN created_at, CHANGE COLUMN created_at_v2 created_at BIGINT UNSIGNED NOT NULL;
代替案としてDATETIME(年9999年まで対応)への移行もあります。UTC基準での扱いやすさを優先するならBIGINT、人間が読める形を残すならDATETIME。
2026年時点でやるべき点検
- 自社プロダクトのDBスキーマ確認:
information_schema.columnsでTIMESTAMPとINTを一覧化、UNIX秒を入れているINTがあれば棚卸し。 - 2038-01-19以降の日付を扱う処理を実装:30年契約のオプション、長期保存の有効期限など。テストケースに
2038-01-20を必ず入れる。 - サードパーティライブラリのアップデート:jwt系、time系、log処理系の依存を最新版に。特にC/C++製ライブラリは要確認。
- 組み込み機器・IoTデバイスのファームウェア棚卸し:自社で配布しているIoT機器、自社で運用しているスマートメーター・産業機器の対応状況確認。
- クラウドベンダーの公式声明確認:AWS・GCP・Azureはいずれも公式に2038年対応宣言済み。ただし利用しているEC2のAMIが古い場合はOS更新を。
64bit time_tの上限はいつ?
64bit符号付き整数の最大値は 9,223,372,036,854,775,807(約9.2×10の18乗)。UNIX秒として日付化すると:
# 64bit time_t の上限 # 約 292,277,026,596 年(西暦292,277,026,596年12月) # 宇宙の現在の年齢(138億年)よりはるかに先 # つまり実質「永久に安全」
64bit化さえ済めば、再び型変更が必要になることは現実的にありません。今のうちに移行を済ませれば、後の世代に問題を残さないのがUNIX時間の良いところです。
補足
- ・本記事は2026-06-16時点の主要OS・DB・言語仕様に基づきます。
- ・組み込み機器の対応可否は各メーカーの公式アナウンスをご確認ください。
- ・移行作業はバックアップ取得・ステージング検証の上で行ってください。本番DB直接ALTERは大規模テーブルでロック発生のリスクがあります。
- ・MySQLの
DATETIMEは内部表現8byteで2038年問題なしですが、タイムゾーン情報を保持しないためアプリ側でUTC統一を推奨。
2038年問題の境界値を変換ツールで試す
2147483647 や 2147483648 を貼って境界の挙動を確認できます:UNIXタイムスタンプ変換