2038年問題
これはMySQLなどのデータベースにも影響を与えます。
特に問題なのが TIMESTAMP 型が2038年問題に対応してないこと
もし TIMESTAMP 型を使い続けると、将来大変なことになるかもしれません。
ということで、MySQLで2038年問題を回避する方法をまとめました。
このページの目次
そもそも2038年問題ってどういう問題?
まず知ってる人も多いけど、2038年問題 について解説
これは 2038年1月19日3時14分7秒 を過ぎると、プログラムが誤作動する問題のことです。
伝統的な実装ではtime_tをintとし、そのintは符号つき32ビットであった。このため最大値は (231 − 1) = 2,147,483,647 となり、取り扱えるのは2,147,483,647秒(≒ 68年)までに限られていた。これを前提として作成されたプログラムは、協定世界時における1970年1月1日0時0分0秒(日本標準時では1970年1月1日9時0分0秒)から2,147,483,647秒を経過した、2038年1月19日3時14分7秒(日本標準時では2038年1月19日12時14分7秒、閏秒は考慮していない)を過ぎると、この値がオーバーフローし、負と扱われる[3]ため、時刻を正しく扱えていることを前提としたコードがあれば、誤作動する。
引用元 : 2038年問題 - Wikipedia
上の説明は Wikipedia から引用したもの
従来だと日時はなぜか 32ビット型 で扱ってたので、それが問題の温床です。
32ビットだと 68年分 しか扱えないので、そのツケがあと数十年後にやってくるということ
もちろん MySQL でも日時を扱うことは当然あります。
なので何も対策してないと、次の例みたいにデータベースがかなり深刻な影響を受けます。
実際にMySQLで2038年問題を疑似再現してみた
MySQLだと TIMESTAMP型 が2038年問題の影響をモロにうけます。
そこで実際に適当なテーブルを作って、2038年を疑似再現をしてみました。
まず 2038年01月19日 03時14分07秒以前 なら TIMESTAMP 型は正常に機能します。
例えば次みたいなテーブルを作ってレコード挿入したとしましょう。
1 2 3 4 5 6 7 8 |
CREATE TABLE Hoge ( id INT NOT NULL AUTO_INCREMENT, _stamp TIMESTAMP, PRIMARY KEY(id) ); INSERT INTO Hoge ( _stamp ) VALUES( '2019-05-26 08:06:19' ); INSERT INTO Hoge ( _stamp ) VALUES( "2038-01-19 03:14:07" ); SELECT * FROM Hoge; |
この SQL 実行の結果は次の通り
1 2 |
1 2019-05-26 08:06:19 2 2038-01-19 03:14:07 |
ここまではOKです、特に問題ありません。
でも問題になるのが 2038年01月19日 03時14分07秒以降の日時 だったとき
例えば次みたいなSQLを発行してみました。
1 2 3 4 5 6 7 |
CREATE TABLE Hoge ( id INT NOT NULL AUTO_INCREMENT, _stamp TIMESTAMP, PRIMARY KEY(id) ); INSERT INTO Hoge ( _stamp ) VALUES( "2038-01-19 03:14:08" ); SELECT * FROM Hoge; |
この結果がどうなるかというと次の通り
1 |
ERROR 1292 (22007) at line 9: Incorrect datetime value: '2038-01-19 03:14:08' for column 'stamp' at row 1 |
こういう風にエラーが出て、レコード自体が挿入できなくなる訳です。
既に動いてるシステムでこんなことが起こったら・・・想像するだけでも恐ろしいですね。
でもこの2038年問題の対処法、MySQLならそんなに難しくありません。
MySQLで2038年問題を超簡単に解決する方法
その解決方法とは、
TIMESTAMP型 を使うのをやめて DATETIME型 に切り替えること
たったこれだけで 2038年問題は簡単に解決できます。
なぜこう言い切れるかというと、リファレンスにこう書いてあるから
DATETIME 型は、日付と時間の両方の部分を含む値に使用されます。MySQL では、DATETIME 値の取得と表示は 'YYYY-MM-DD HH:MM:SS' 形式で行われます。サポートしている範囲は '1000-01-01 00:00:00' から '9999-12-31 23:59:59' です。
>TIMESTAMP データ型は、日付と時間の両方の部分を含む値に使用されます。TIMESTAMP には、'1970-01-01 00:00:01' UTC から '2038-01-19 03:14:07' UTC の範囲があります。
赤字で強調したところに注目してください。
この説明の通り、 DATETIME を使えば9999年まで日時を問題なく扱えるんです。
つまり次に日時が問題になるのは 西暦10000年 ってことですね。
その頃になったら 「10000年問題がヤバい!」 とか言って騒がれてるかも・・・
まあ今開発してるシステムを10000年まで動かす予定がないなら大丈夫です。
これを使えば、2038年以降の日付も問題なく扱えます。
例えば次が先ほどのSQLを DATETIME型 で書き換えたもの
1 2 3 4 5 6 7 |
CREATE TABLE Hoge ( id INT NOT NULL AUTO_INCREMENT, _datetime DATETIME, PRIMARY KEY(id) ); INSERT INTO Hoge ( _datetime ) VALUES( "2038-01-19 03:14:08" ); SELECT * FROM Hoge; |
この実行結果は次の通り
1 |
1 2038-01-19 03:14:08 |
はい、ちゃんと問題なく動いてくれてます。
以上が MySQL で2038年問題を回避する方法
今動いているシステムだと難しいですが、これから作るシステムなら簡単に対策できます。
補足 : PHPでも2038年問題には注意しよう!
ここまでが MySQL での2038年問題の回避策
もちろんMySQL以外に、PHP などでも問題が起こります。
その PHPでの2038年問題回避策 は次記事でまとめたので、良ければご覧ください。
PHPにはTIMESTAMP型はないです。
でもdate関数が 2038年問題 の温床になるので要注意ですね。
ここまでのまとめ
ということで簡単なまとめ
- TIMESTAMP型は使ったらダメ
なぜなら内部的に日時を32ビットで扱っているため。2038年01月19日 03時14分07秒 より大きな日時を代入すると誤作動の原因に。絶対使っちゃダメ!
- 代わりにDATETIME型を使えばOK
リファレンスによると DATETIME型 は 9999年 まで対応している。日時を扱うならこちらを使う方が安全だし2038年問題も解決できる
MySQLでは絶対に TIMESTAMP型 を使わないように要注意!
以上、MySQLでの2038年問題の回避方法についてでした。ではでは(^_^)/~