2000年問題より恐い2038年問題

もう2000年まで1年を切りました。巷のニュースでも結構取り上げられ、ちょっとは有名になった2000年問題ですが、あなたの会社で動いているコンピュータソフトの点検はもうお済みですか? なんて、私の勤めている会社ではたくさんコンピュータがありすぎて、本当に大丈夫なのかなぁ、と思っています。

2000年問題は、一言で言ってしまえば、けちって西暦4桁のうち下2桁だけで西暦を表現しようとした、ただそれだけです。1999年は98と入力して1998年を入力したつもりになっていただけ。00と入力したら2000年を入力したようにプログラムをちょっと換えればいいわけです。 が、理由はともかく4桁を2桁にケチケチした結果がこれなわけで、データに記録する幅もケチって2桁ぶんしか用意してなかったら、もっと面倒なことになりそうですよねぇ。001223は2000年12月23日なのか、2100年12月23日なのか区別つかなくなるわけだし。

それでも、あと100年も電気で動くコンピュータが世の中に存在しないかも知れないし、100年も経てばそのプログラム作った人も亡くなっていて、責任云々問われる心配もない。そもそも100年もしたらコンピュータなんてなくなって、なにか別のすごいものが世界中で動いているかも知れない。だからこの2000年問題の対処方法としてプログラム設計者は「00は2000年と判断するように、ちょっと直しておくか」程度で済むでしょう。

しかし、あと38年ぐらいなら、コンピュータはまだ電気で動いていて、いまプログラムしている貴方もきっと生きているはず。私は33歳(だったかな?)だから38年すると71歳になっている。このころは定年が75歳ぐらいまで延びているかも知れないから、もしかしたらまだ会社勤めをしていて、次の事件がおこったら首が飛ぶかもしれない!(こんな年になって首になってもぜんぜん堪えないだろうが)

よくプログラムに使われるプログラム言語にC言語というのがある。これに標準て付属している標準ライブラリというなかには、時間に関する関数がいくつか用意されていて、秒単位の時間を表す変数の型としてtime_tというのがある。(そんなこといちいち説明しなくても知っている人にはかったるいのだけど、知らない人のためにね)
time_tというのは32ビットで現す変数で、それも符号付きなので10進数では0〜2147483670まで表現できる。つまり2147483670秒までカウントできるわけだ。time_t変数のお約束で、0は1970年1月1日0時を現すことになっている。日本時間では時差があるので1970年1月1日9時が0となる。

ここまでくれば大体想像がつくと思うけど1970年1月1日9時に2147483670秒を足すと2038年1月19日12時14分7秒になり、これがtime_t変数が表現できるもっとも未来である。だからこの時刻を超えると2000年問題より深刻な不測の事態がコンピュータに起こるのは容易に想像できる。

time_tが32ビットで符号付きだから符号なしにして更に倍の2116年ぐらいまで動くんじゃないの?大丈夫だよ。なんて甘い考えを起こしちゃいけない。なぜならtime_t変数を扱う関数は2147483670秒を超えるとエラーを起こすようになるから。例えば世界標準時をローカル時間に変換してくれるlocaltime関数はNULLという値を返すようになり、それを参照した途端にプログラムはエラーする。time_t変数を日付文字列に変換してくれるctime関数もNULLを返すようになり、どうしようもなくなる。そんなわけで、ごく簡単な下のプログラムは2038年を超えるとぶっ飛んでしまうわけです。

あー 恐ろしや、2000年問題ぐらいは考慮にいれて最近のプログラムは作られているだろうが、2038年問題までは対処していないだろうなぁ。だってどう対処すればいいかわからないんだもんね。誰が解決案を出してくれるのだろう、C言語の規約を作っているANSI委員会だろうか?たとえ32ビットが64ビットになったって、今そこにあるプログラムはコンパイルしなおすか作り直さない限り直らないんだけど。

とまあ、チューチューマウスが2000年問題に対応してますか?という質問がきたので、そりゃ問題ないね!でも2038年は。。。。とちょっと考え込んでしまったわけでした。

#include "stdafx.h"
#include <time.h>

int main(int argc, char* argv[])
{
time_t t = 0;
printf( "0の時刻は %s", ctime( &t ) );
struct tm ltm = *localtime( &t );
printf( "%d年%d月%d日%d時%d分%d秒\n\n",
ltm.tm_year+1900,
ltm.tm_mon+1,
ltm.tm_mday,
ltm.tm_hour,
ltm.tm_min,
ltm.tm_sec );

t = 0x7fffffff;
printf( "0x7fffffffの時刻は %s", ctime( &t ) );
ltm = *localtime( &t );
printf( "%d年%d月%d日%d時%d分%d秒\n\n",
ltm.tm_year+1900,
ltm.tm_mon+1,
ltm.tm_mday,
ltm.tm_hour,
ltm.tm_min,
ltm.tm_sec );

t = 0x80000000;
printf( "0x80000000の時刻は %s", ctime( &t ) );
ltm = *localtime( &t );
printf( "%d年%d月%d日%d時%d分%d秒\n\n",
ltm.tm_year+1900,
ltm.tm_mon+1,
ltm.tm_mday,
ltm.tm_hour,
ltm.tm_min,
ltm.tm_sec );

t = 0xffffffff;
printf( "%d年%d月%d日%d時%d分%d秒\n\n",
ltm.tm_year+1900,
ltm.tm_mon+1,
ltm.tm_mday,
ltm.tm_hour,
ltm.tm_min,
ltm.tm_sec );

return 0;
}