「2038年問題」を華麗に解決!~エンジニアの仕事~
皆さんこんにちは。R&D事業部 チャンウクです。
今日付け、すなわちこの投稿でブロガーデビューさせていただきます。
私の投稿では主にシステム開発時のエピソードや勉強内容についてお話したいと思います。
さて、皆さん、「2038年問題」はご存知でしょうか。
初耳の方もいらっしゃると思いますが、
今回は世間に2038年問題として知られているバグを処理、解決した事例を紹介します。
■ 概要
今、R&Dでは社内で使う 【業務支援ツール】を開発しております。
全社員の日々の業務を扱うため、カレンダーを使ったページが多いです。
■ 問題発見
実装したカレンダーの単体テストを行っている際、こんな表示がでました。
!?!?
2038年1月の次は、1970年1月!?
一体どうしたものでしょうか。
分析してみましょう!
■ 原因分析
業務支援ツール開発では、日付の調整をするためにPHP(Web開発でよく使用されるスクリプト言語の一種)の「strtotime(※)」と「date(※)」というメソッドを使っています。
unixtimeというのは、基準日である1970.01.01 00:00:00から何秒過ぎているかを表す定数のことです。
Unixは1970年はじめに開発されたもので、最大限の数字をunixtimeに使うため、エポック(基準)を1970年1月1日にしているそうです。
unixtimeは32bitの定数で定義されているので、その範囲は 2の32乗 → 4,294,967,295
つまり、
最小は基準日から – 2,147,483,648
⇒ 1901年 12月 13日 金曜日 20時 45分 54秒
最大は基準日から +2,147,483.647
⇒ 2038年 1月 19日 火曜日 3時14分07秒
※最初のbitは符号bitで使用。
となります。
このunixtimeが32Bitの最大表現限界である2,147,483,647まで増加すると、次はどうなるか分かりますか?
コンピューターではデータの表現範囲を超えることが発生すると、該当範囲の最小に戻るように処理される特徴があります。
それをOverFlowと呼びます。
簡単にいうと、値xの範囲が 0 ≦ x ≦ 99 のとき、99の次の値は100ではなく0になる仕組みです。
つまり、2,147,483,647の次は2,147,483,648ではなく、最小値の-2,147,483,648になってしまうのです。
このように、2038年 1月 19日 火曜日 3時14分08秒 以降の時間が表示できなくなってしまうのが、2038年問題です。
ですが、なぜ私たちのプログラムは最小値の1901年ではなく、基準値の1970年に戻ってしまうのでしょうか。
OverFlowは、プログラムの安全性と信頼性のに直結します。
PHPのstrtotimeでは、OverFlowの防止のため、
表現範囲を超える値の変換リクエストが送られると、
メソッド内部でエラーケースと認識し、false(偽)を返すように処理されています。
下記のコードは、2038年1月に1ヶ月プラスした、OverFlowが発生しているコードです。
date(‘format’, strtotime(‘2038-1’ + 1 month));
エラーケース処理でfalseを返すので、
date(‘format’, false);
このようになります。
そして、コンピューターではfalse == 0と処理されるので、
date(‘format’, 0);
基準値「0」である、1970年1月1日が表示されてしまうということなのです。
(正確には、UTC+9を適用して 1970.1.1 09:00:00)
■ 解決
この2038年問題は、プログラムを作成するときunixtimeに64bit定数を使うだけで解決できます。
実際64bitのPHPはUnixTimeが64Bitになっているのが確認できます。
問題が起きたメンバーのPCは、64bitのWindowsだったのですが、
開発には32bitのPHPしか入っていないXAMPP(開発環境)をつかっていて、unixtimeが32 bitになってしまっていました。
開発環境上では気持ち悪いですが、本番環境のサーバでは64bitになるので問題ありません。
我慢することで解決にしましょう!!
・・・で終わるとマズイ。
クロスプラットフォーム対応(仕様が全く異なるシステム上で、同じ仕様のものを動かすことができるようにすること)を実施します。
PHPは5.2以上のバージョンからDateTime Classを提供しています。
DateTime Classは各年月日時分秒を、それぞれ個別の変数を使って保存するので、
32bitの環境でも2038年以上のDate表現ができます。
それだけでなく、
・Timestampを使わなくても日付の加減及び比較が簡単にできる
・タイムゾーン変更が簡単にできる
メソッドを提供しています。より簡単に日付データが処理できます。
strtotimeを全てDateTimeに切り替えて実装すると・・・
ローカル開発環境上でも問題ない!対応済み!
このように、2038年問題は上手く解決することができました。
次は64bitの上限である2922億7702万4641年問題に対応しなければなりません。(笑)
この問題は、2922億7702万4641年後に取り上げます!
どうですか? 楽しそうでしょう?笑
そう思った方はぜひR&D事業部に遊びに来てください!