皆さんこんにちは。R&D事業部 チャンウクです。

今日付け、すなわちこの投稿でブロガーデビューさせていただきます。
私の投稿では主にシステム開発時のエピソードや勉強内容についてお話したいと思います。

さて、皆さん、「2038年問題」はご存知でしょうか。

初耳の方もいらっしゃると思いますが、
今回は世間に2038年問題として知られているバグを処理、解決した事例を紹介します。

■ 概要

今、R&Dでは社内で使う 【業務支援ツール】を開発しております。
全社員の日々の業務を扱うため、カレンダーを使ったページが多いです。

■ 問題発見

実装したカレンダーの単体テストを行っている際、こんな表示がでました。

s_写真B

!?!?

2038年1月の次は、1970年1月!?

あれ?

一体どうしたものでしょうか。
分析してみましょう!

■ 原因分析

業務支援ツール開発では、日付の調整をするためにPHP(Web開発でよく使用されるスクリプト言語の一種)の「strtotime(※)」と「date(※)」というメソッドを使っています。

strtotime
日付フォーマットの文字列をunixtime(コンピュータシステム上の時間表現)に変換する

date
unixtimeを、指定した日付フォーマットの文字列に変換する

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になってしまうのです。

写真OF

このように、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に切り替えて実装すると・・・

s_写真S

ローカル開発環境上でも問題ない!対応済み!

AHA!

このように、2038年問題は上手く解決することができました。

次は64bitの上限である2922億7702万4641年問題に対応しなければなりません。(笑)
この問題は、2922億7702万4641年後に取り上げます!

どうですか? 楽しそうでしょう?笑
そう思った方はぜひR&D事業部に遊びに来てください!