あちこちで話題になってる2038年問題
コンピューター内部(というか言語内部)で扱うデータ型が問題で起こるみたいです。
もちろんPHPの場合も、対策しないとかなりヤバい影響を受けてしまいます。
ということで、 PHPでの2038年問題の回避策とコード例 をまとめてみました。
このページの目次
そもそも2038年問題とは?何が問題なの?
まず 2038年問題 について簡単に解説
これはその名の通り、2038年を超えるとコンピューターが誤作動するという問題です。
以下 Wikipedia からの説明引用
伝統的な実装では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
古いOSだと時間を 32ビット で扱うことが多かったです。
でも32ビットで扱えるのは 2,147,483,647秒(≒ 68年)まで
標準時から数えて約68年が 2038年1月19日3時14分7秒 という訳です。
つまりこういうこと
- 32bitでは68年分の日時しか扱えない
- 2038年問題は日時を32bitで扱うと起こる
今までだと 68年分 しか扱えなかったとは・・・
もちろんPHPにも日時型は存在するんで、次みたいに深刻な問題が出てきます。
2038年問題がPHPに与える悪影響&コード例
PHPで問題が起きるのは date関数 を使って日付をフォーマットする時
この関数は内部的に32bitで扱ってるので、2038年を超えると変な動作をします。
実際どういう誤作動をするかは次コードの通りです。
まず初めに 2038年問題 でギリセーフな、 2038/01//19 03:14:07 をdate関数でフォーマット
1 2 3 |
/// 2038/01/19 03:14:07 秒をフォーマット $timestamp = date( 'Y-m-d H:i:s', 2147483647 ); print_r( $timestamp ); |
表示されるフォーマット日時は次の通りです。
1 |
2038-01-19 03:14:07 |
まあ当たり前と言えば当たり前、当然の動作です。
で・す・が、
この日時を1秒でも超えると問題が出てきてしまいます。
例えば2038年を過ぎた 2039-01-01 をフォーマットしてみました。
1 2 3 4 5 6 7 8 |
$dateString = '2039-01-01'; $format = 'Y-m-d H:i:s'; // UNIXタイムスタンプに変換 $date = strtotime( $dateString ); /// フォーマットして表示 echo date($format, $date); |
このコードがどういう結果を返すのか・・・
その答えは次の通り
1 |
1970-01-01 00:00:00 |
なんと 1970-01-01 と表示されてしまいました。
これはさっき書いたみたいに date 関数では32bitで日時を扱うため
1秒でも32bitを過ぎると、こういう風にオーバーフローしてしまうみたいです。
PHPでの2038年問題の簡単な回避法
じゃあPHPでのこの2038年問題はどう回避すればいいのか・・・
その答えは単純で、 DateTime型 で日時を扱えばいいだけです。
なぜならDateTime型は 年、月、日、etc‥ を全て個別に扱っているため。
なので2038年を超えようが全く問題ないということです。
例えば DateTime型を使って、
次みたいに
2038-06-09 08:40:01 をフォーマットするコードを書いてみました。
1 2 |
$date = new DateTime( '2038-06-09 08:41:01' ); echo $date->format( 'Y-m-d H:i:s' ); |
もし date関数を使ってるならアウトです。
でも DateTime を使ってるので、次みたいに正常に表示されます。
1 |
2038-06-09 08:41:01 |
これが PHP での2038年問題の回避法
あとそれから、DateTime型で使う関数には色々エイリアスもあります。
例えばその一例を上げるなら次の通り
- date_add 関数
- date_create 関数
- date_format 関数
- date_modify 関数
- date_sub 関数
こういうのも DateTime で日時を扱えるので、問題ありません。
PHPリファレンスなどで「返り値がDateTime型」と書いてあれば大丈夫です。
MySQLでも2038年問題の対策は必須!
ここまでがPHPでの2038年問題の回避策
もちろん MySQL でも日付を扱うことは多いので、対策が必要になります。
その MySQLでの2038年問題への回避策 は次記事でまとめた通り
MySQLの場合、TIMESTAMP型 は使わないようにすべきです。
詳しい対策方法が知りたい人はご覧ください。対策自体は簡単なので
ここまでのまとめ
ということでPHPでの2038年問題のまとめ
- date関数は使っちゃダメ
この関数は内部的に日時を32ビットで扱う。そのため 2038年01月19日19日3時14分7秒 を超えた時点で誤作動してしまう。絶対使ってはダメ!
- 代わりに DateTime を使おう
このクラスは 年・月・日、時・分・秒 それぞれで個別にデータを扱う。なので2038年を超える日時を扱うことが可能(9999年まで取り扱える)
以上、PHPでの2038年問題の回避策についてでした。
絶対にWeb開発では date関数 は使ってはいけません、要注意です!