Table of Contents
「2038年にはコンピュータの時間がおかしくなって色々なトラブルが起こる」という話を聞いたことがあるかも知れません。
いわゆる「2038年問題」と呼ばれるもので、これが何故起こるのか、それによる影響やどういう回避策が考えられているのかについて紹介します。
2038年問題とは
プログラミング言語の一つである C言語 の時刻を計算する関数や、Linux などのベースのシステム(OS)となっている UNIX は、世界標準時の 1970年1月1日 午前0時00分00秒 から何秒経過したかによって日時を算出しています。
そして、その経過秒数は「32bit符号付き整数」(プログラム的に言えば signed int)として記録されています。
「32bit符号付き整数」は、正の数を表現するために、2進数で31桁を使って整数を表現する方式です。
32桁ではないのは、符号で1桁分が使用されるためです。
つまり、表現できる最大の秒数は、2の31乗から 1 を引いた数である 2147483647秒 までです。
$$2^{31} – 1 = 2147483648 – 1 = 2147483647$$
時々、この最大値を 2147483648 と書いている文献がありますが、それは誤りです。
基準となる日時である 1970年1月1日 午前0時00分00秒 から 2147483647秒後 の日時は、2038年1月19日 午前3時14分08秒(日本時間では 2038年1月19日 午後12時14分08秒)です。
しかし、この最大値より 1 大きい値である 0x80000000 は 2147483648 とはならず、負の値を表す(符号で使われているbit桁の部分が変わってしまう)ため、1901年に逆戻りします。
2進数で表現すれば、正の数の最大値は以下のようになります。
$$01111111111111111111111111111111 = 2147483647$$
これに 1 を足すと、最初の桁(最上位ビットやMSBとも呼ばれます)が繰り上がりますが、符号付き整数においては、この最初の桁は符号を表す桁であって、数値を表す桁ではないため、符号の反転が起こります。
$$10000000000000000000000000000000 = -2147483648$$
「32bit符号付き整数」の範囲は「-2147483648 〜 2147483647」なので、このマイナスの値が呼び出されてしまうことが、時刻が過去に遡る原因です。
以上のことから、2038年1月19日 午前3時14分08秒 以降、時刻に依存するシステムに問題が起きるのではないかと危惧されています。
2038年問題による影響
実際に、一部銀行のATMで、この2038年問題によって影響が出た例が報告されています。
2038年問題による影響はすでに広く報道されている。1月11日に23行の銀行でATM(現金自動預払機)が一部の取引で正常に利用できなくなったトラブルの原因が、この2038年問題によるものだった。
この問題が起きた銀行はいずれも日本IBMのソフトを使っていたが、このソフトの内部に、時刻の2倍に足し合わせる処理があり、ちょうど1970年と2038年1月19日の2分の1を超えた2004年1月11日の朝から、2038年問題が顕在化して、システムが正常に稼動しなくなった。
ニュース – 【スクープ】コンピュータの“西暦2038年問題”発生、早くも日本を揺るがす:ITpro
様々な企業において影響が確認されていますが、2038年問題がきっかけとなった最も社会的影響の大きかった問題は KDDI の利用料金誤請求であると言われています。
実際の不具合にはいくつかのパターンが見いだせる。インターネットイニシアティブ(IIJ)や日本IBM、システム・インテグレータのトパックスは自社製品で、桁あふれを考慮せずに2種類の経過秒数を足し合わせる処理を行った。ポータル・サイトのgooを運営するNTT-X(4月1日からはNTTレゾナントに運営が移行)やKDDI、CADソフト大手のPTCジャパンなどは、プログラミングの際に経過秒数の最大桁数を間違えて設定した。最大桁数を1桁間違えると、1970年と2038年の中間に当たる2004年1月10日で桁あふれが起きてしまう。
…
「いわゆる“西暦2038年問題”が原因だ」。KDDIは3月5日、国内電話サービスの料金を誤って請求した原因について、本誌にこうコメントした。誤請求が生じたのは1月10日から2月25日に利用した通話の一部。影響範囲は通話数にして4万5866件、総額は約1346万円分におよぶ。
ITレポート(動向/解説) – 「西暦2038年問題」でトラブル相次ぐ:ITpro
2038年問題の対策
macOS はUNIXベースですが、時刻の基準を変更(NSDateクラスの基準時刻を世界標準時の 2001年1月1日 午前0時00分00秒)したため、この問題が起こることはないと考えられています。
NSDateクラスには、1970年を基準とすることができるメソッド dateWithTimeIntervalSince1970 が用意されているため、互換性を保つこともできます。
近年のシステムでは、「32bit符号付き整数」の代わりに、さらに大きな数値を扱える「64bit符号付き整数」を使えるようにしたものが登場しています。
改善が必要なもう1つの分野は、日付です。Linuxでは、日付は1970年1月1日からの秒数を表す符号付き32ビット整数として表現されます。これは2038年に負になります。しかし、64ビット・システムでは、日付は符号付き64ビット整数として表現され、使用可能な範囲が延長されます。
Linuxアプリケーションの64ビット・システムへの移植
余談
「32bit(ビット)符号付き整数」は「4byte(バイト)符号付き整数」とも呼ばれることがあります。それはビットとバイトの関係が以下のようになっているからです。
$$1バイト(byte) = 8ビット(bit)$$
また、2147483647 を16進数で表記すると 7fffffff となります。