注目キーワード
  1. 技術
  2. 広告
  3. IDFA
  4. PHP
  5. WordPress

2038年問題、phpではstrtotime(date関数)に注意しましょう

  • 2021年1月4日
  • 2021年1月8日
  • 技術
  • 0件

数年前から話題になっている2038年問題について、少しずつ近づいてきました。
日々実装をするプログラムでもそろそろ気にしていかないといけない頃かと思いますので、まとめておきます。
2038年問題ですが、シンプルに言うと、コンピュータで扱うデータ型で問題が起きてしまい、phpで実装するエンジニアも対策をしないと影響を受けてしまう問題になっています。

2038年問題とは何か

https://ja.wikipedia.org/wiki/2038%E5%B9%B4%E5%95%8F%E9%A1%8C

wikipediaの引用になりますが、

伝統的な実装ではtime_tをintまたはlongのtypedefによる型エイリアス(別名)とし、その型は符号付き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秒、閏秒は考慮していない)を過ぎると、この値がオーバーフローし、負と扱われるため、もし時刻を正しく扱えていることを前提としたコードがあれば、誤動作する。

と書かれています。つまり、32ビットで扱えるのは、2,147,483,647秒(≒ 68年)までで、これを前提にしたプログラムは、標準時間から68年経過した2038年1月19日3時14分7秒になっています。そのため、これを超えてしまうと誤動作してしまうということになります。

date関数 / strtotimeが危ない

phpで、2038年問題の影響を受ける場面は、date関数を用いて日付をフォーマットするときに、影響を受けます。date関数は、内部的に32bitで処理しているため、2038年を超えると意図しない動作をします。

通常だと、下記のようなコードは問題なく動くのですが、

$date = date('Y-m-d H:i:s', strtotime('2037/01/01 00:00:00'));
print_r($date);

2037-01-01 00:00:00 と表示されます。
しかしながら、2039年だと、

$date = date('Y-m-d H:i:s', strtotime('2039/01/01 00:00:00'));
print_r($date);

1970-01-01 00:00:00 と表示されます。先ほども記載した通り、date 関数では32bitで日時を扱うため、1秒でも32bitを過ぎると、このようになってしまいます。

2038年問題の回避方法

64ビットでコンパイルされているphpを使う

利用しているOSが64ビットで、「PHP」自体が 64bit ビルドにすることで回避することが可能です。

DateTime型を使う

DateTime型 で日時を処理する方法もあります。
DateTime型は、年、日などのデータをそれぞれ別々に扱っているため、今回の2038年問題の影響を受けません。
そのため、下記のようなコードで回避することができます。

$date = new DateTime( '2039-01-01 00:00:00');
print_r $date->format('Y-m-d H:i:s');

2039-01-01 00:00:00 の結果になりました。