解説:教えて那々子先生
2038年問題はなぜ起こる?
UNIX時間は、UNIX系のOS(Unix、BSD、Linuxなど)で採用されている時刻の表現方法で、世界協定時(UTC)で1970年01月01日 0時0分0秒からの(閏秒を除いた)経過秒数で時刻を表します。この時刻表現方法は、UNIX系のOSだけでなく、C言語の多くの処理系でtime_t
型の内部表現としても採用されています。
多くの処理系で事実上UNIX時刻が採用されていますが、time_t
型について、C99(ISO/IEC 9899:1999)では「which are arithmetic types capable of representing times」、C11(ISO/IEC 9899:2011)規格では、「which are real types capable of representing times」とのみ定められています。そのため、UNIX時刻ではない場合や整数型でない場合も考えられます。
時刻の表現にUNIX時間を用い、なおかつデータの格納に符号付き32ビット整数を用いているシステムでは、2038年01月19日 午前3時14分7秒に最大値に達し、同8秒でオーバーフローが発生します。その結果、マイナスの数値となり、最小値である1901年12月13日 20時45分52秒にジャンプしてしまうのです。
時刻(UTC) | 10進数 | 2進数 |
---|---|---|
1970/01/01 00:00:00 |
0 |
00000000000000000000000000000000 |
1970/01/01 00:00:01 |
1 |
00000000000000000000000000000001 |
1970/01/01 00:00:02 |
2 |
00000000000000000000000000000010 |
略 | ||
2038/01/19 03:14:05 |
2147483645 |
01111111111111111111111111111101 |
2038/01/19 03:14:06 |
2147483646 |
01111111111111111111111111111110 |
2038/01/19 03:14:07 |
2147483647 |
01111111111111111111111111111111 |
1901/12/13 20:45:52 |
-2147483648 |
10000000000000000000000000000000 |
その結果、時刻順でソートする処理で想定外の動きになったり、処理対象のデータが検索でヒットしなくなる、データチェックで不正データと判定されるなど、色々な不具合が発生するのです。
さらに厄介なのが、日本時刻では平日の日中という業中まっただ中に発生するということです。そして、日付がジャンプすることにより、火曜日が突然木曜日になってしまうことから、バッチの実行スケジュールにも大きな影響が生じ得ます。
2000年問題よりもさらに深刻なのは、UNIX時間かつ符号付き32ビット整数を採用しているシステムが非常に多いことです。
例えば、Linuxカーネル5.6よりも前の32ビット版Linuxも2038年問題を抱えていました。また、ext3ファイルシステムでは、ファイルの更新時刻に2038年01月19日 午前3時14分8秒以降の時刻を記録できません。しかし、そもそも「ファイルシステムに何を使用しているか?」を意識していないユーザーも多く、充分な対応を行わないまま2038年を迎えてしまう……ということもあるかもしれません。
現在は、多くのC言語の処理系で、time_t
型に符号付き64ビット整数が採用されていますが、昔コンパイルされたプログラムはその恩恵にあずかることができません。修正にはソースコードの変更と再コンパイル、場合によっては入出力データ仕様にも変更を加える必要があります。したがって、そもそもソースコードが残っていないようなソフトウェアではもはや対応できない可能性があるということなのです。
また、64ビットのtime_tを使っているから2038年問題に対応していると思っていても、システムの一部に非対応のプログラムが混じっていると、異常動作が引き起こされることがあります。例えば、32ビットのtime_tの値がオーバーフローでマイナスになってしまえば、その後で、その値を64ビットのtime_tに代入してもマイナスのままだからです。