2038年問題
2038年問題(にせんさんじゅうはちねんもんだい)は、協定世界時(UTC)2038年1月19日3時14分7秒(日本標準時の場合、1月19日12時14分7秒)を過ぎると、コンピュータが誤動作する可能性があるとされる年問題。
経緯
[編集]コンピュータおよびコンピュータプログラムにおける時刻の表現として「UNIX時間」《協定世界時における1970年1月1日0時0分0秒からの経過秒数[注釈 1]》を採用しているシステムがある。
UNIXおよびUNIX派生のオペレーティングシステム (OS) における基幹ソフトウェア部品の多くはC言語で書かれているが、前述の経過秒数を表現する型は、現在の標準では、「time_t型」である。C言語の標準である「ISO/IEC 9899:1999」では、time_t
型の範囲や精度はいずれも実装定義としている[1]。UNIXの標準 (POSIX) には「shall be integer or real-floating types.」とのみ記述があり、ビット幅および値の範囲については何らの定めも無い。
伝統的な実装ではtime_t
をint
またはlong
のtypedefによる型エイリアス(別名)とし、その型は符号付き32ビット整数型であった。このため最大値は (231 − 1) = 2,147,483,647 となり、取り扱えるのは2,147,483,647秒(≒ 68年)までに限られていた。これを前提として作成されたプログラムは、協定世界時における1970年1月1日0時0分0秒(日本標準時では1970年1月1日9時0分0秒)から2,147,483,647秒を経過した、2038年1月19日3時14分7秒(日本標準時では2038年1月19日12時14分7秒、閏秒は考慮していない)を過ぎると、この値がオーバーフローし[注釈 2]、もし時刻を正しく扱えていることを前提としたコードがあれば、誤動作する。
ある実装におけるtime_t
の型を変更することだけであれば、プログラム中のたった1箇所 (typedef) を書き換えるだけであるが、実際の運用では、アプリケーションプログラムにおける時刻の扱い全てが正しくある必要がある。また、すでにあるデータ構造中で32ビット固定長として割り当てられていれば、問題が発生する。たとえば、Linuxのファイルシステムであるext2・ext3・ReiserFSのタイムスタンプは同日付までしか対応していない。
この期日以前でもプログラムで内部的にこの制限を超えた時刻データを扱おうとすれば同様のエラーが発生するため、たとえばちょうど半分を経過した2004年1月11日にはすでにATMの誤動作といったトラブルが発生した[2]。この事例ではプログラム中のある時刻と別の時刻の中間の時刻を求めるような処理で、相加平均を単純に求める のような式を利用していたものとみられる[注釈 3]。他にも顕在化していないトラブルが今後表面化するという可能性はあり得る。
2000年問題はアプリケーションレベルでの修正が可能であったが、この問題は現在普及しているC言語処理系やOSのAPIといったシステムの深い層に潜む問題であるため、2000年問題より深刻であるという指摘もある[3]。
対策
[編集]対策としては、time_t
型を符号付き64ビット整数型(一般にはlong long int
型)にするという方法がある。符号付き64ビット整数型の場合、上限は9,223,372,036,854,775,807(263 − 1)である。これを年数に変換するとおよそ西暦3000億年[注釈 4]まで使用できるので、事実上問題が発生することはない。64ビット版のオペレーティングシステムや処理系では、time_t
型は符号付き64ビット整数型で表されるようになってきている。UNIXベースのOSでは、64ビット版でtime_t
も併せて64ビット化されることが多い。
何らかの事情によりtime_t
を64ビット化できない環境に対しては、time_t
を符号無し32ビット整数型(一般的にはunsigned long int
型)にするという回避策が使われることもある。この場合、上限は4,294,967,295(232 − 1)となり、2106年2月7日6時28分15秒(閏秒を考慮しない場合)まで表現可能になる。従って2038年問題は回避できるが、結局2106年には問題が発生するため、あくまで64ビット化が困難な環境に限って適用すべき方法とされる。
macOS (Mac OS X 10.0) ではNSDate
クラスにて協定世界時の2001年1月1日0時ちょうどをエポックタイムとして刷新し[4][5]、また経過時間の内部表現として倍精度浮動小数点数を用いるようになったため[6]、これらを使用している限り、2038年については問題を回避できる。なお、macOS Mojaveは32ビットアプリケーションを動作させることのできる最後のバージョンとなり、macOS Catalinaでは起動することができなくなった[7]。
32ビット版のMicrosoft Windows (Win32) では内部時刻の表現に64ビット化されたFILETIME
構造体[8]を使っており、time_t
を使っているわけではない。そのため、Windows OS側に関しては、旧OSに関する一部のケースを除き[9]、32ビット版であっても2038年問題は発生しない[10]。ただし、Microsoft C/C++ (MS-C) および古いバージョンのMicrosoft Visual C++ (MSVC) においては、time_t
は32ビットのlong int
を使って定義されていたため、これらの古い処理系のC/C++ランタイムライブラリ (CRT) を利用して構築されたアプリケーションソフトウェアやDLLなどは、2038年問題を抱えていることになる。x64アーキテクチャの64ビット版Windows OS上ではWOW64サブシステムによりx86アーキテクチャ向けに構築された32ビットアプリケーションも動作させることができるが、古い32ビットアプリケーションにおける2038年問題は、たとえWindows OSを64ビット版に入れ替えたとしても回避することはできない。Microsoft Visual C++ 2005以降では、既定でtime_t
は__time64_t
と等しく[11]、32ビットアプリケーションであってもtime_t
は64ビット化されるため、古いアプリケーションを新しい処理系およびランタイムで構築し直せば2038年問題を回避できる。
関連した問題
[編集]- 時刻aと時刻bのちょうど中間の時刻を求める時、それぞれのUnixタイムをTaとTbとして、(Ta+Tb)/2 と計算すると、2038年問題の半分以降が経過していればTa+Tbの計算でオーバーフローし、誤った結果となる。これは1,073,741,824 秒目で、2004年1月10日13時37分4秒以降がこの場合に相当する。2004年1月10日あるいは11日に、この事例と推察される報告があった[12]。 この問題を回避するためには、計算方法を工夫する必要がある。例えば、時刻の中間を求める際に、オーバーフローを避けるために次のような方法が考えらる:
- 時刻の差を計算する: まず、時刻bから時刻aを引いて、その差を求める。
- 差の半分を求める: 求めた差を2で割る。
- 時刻aに加える: 最後に、時刻aに差の半分を加えることで、中間の時刻を求める。 この方法を数式で表すと、次のようになる: 中間時刻=Ta+(Tb−Ta)/2
類似する年問題
[編集]- 2001年9月9日問題は、2001年9月9日にtime_t型の値が9億秒から10億秒と桁が増えることに伴う問題。time_t型の値を文字列(辞書順)でソートしていたことで、「9億 > 10億」と判断され、項目の新旧が正しく判断されず、新しく作られた項目が表示されない、古いものとみなされ削除されるなどの問題が発生した。
- NTPなど、1900年1月1日からの積算秒数で時間を表現するシステムもあり、符号なし32ビットの値が2036年2月7日6時28分15秒 (UTC) を超えるとオーバーフローすることによって問題が発生する(→2036年問題)。SNTPv4を定めたRFC 4330には、最上位ビットが0の場合は時刻が2036年から2104年の間であるとみなして、2036年2月7日6時28分16秒 (UTC) を起点として計算することで2036年問題を回避する方法が書かれている。
- 2038年4月23日問題 - ユリウス通日を内部日付表現に用いる物のうち、基準日(グレゴリオ暦1858年11月17日正午)からの修正ユリウス日(MJD)を使用し、かつ16ビットで処理しているシステムでは、日数が16ビットからあふれるために問題が起こる。
- 2038年11月21日問題 - GPSは内部処理で週数を10ビットで管理しており、起点である1980年1月6日から3072週後にあふれて0に戻る。(10ビットでは3回目)
- 2040年問題 - UNIX系システムで使用されるtime_t型の値が、2040年1月1日にオーバーフローする可能性がある。これは、32ビットの符号付き整数で表現されるtime_t型が、1970年1月1日からの秒数をカウントしているためである。この問題を回避するためには、64ビットのtime_t型に移行する必要がある。
- 2050年問題 - 一部のシステムでは、2050年を超えると日付の計算に問題が生じる可能性がある。これは、システムが2桁の年数を使用しているためであり、2050年以降の日付を正しく認識できないことが原因である。
- 2100年問題 - グレゴリオ暦の閏年計算に関連する問題である。通常、4で割り切れる年は閏年であるが、100で割り切れる年は閏年ではない。ただし、400で割り切れる年は再び閏年となる。2100年は100で割り切れるが、400では割り切れないため、閏年ではない。このため、一部のシステムでは2100年を閏年と誤認識する可能性がある。この問題を回避するためには、システムの閏年計算ロジックを修正する必要がある。
脚注
[編集]注釈
[編集]- ^ 「ただし、うるう秒を無視して現在時刻から逆算した値を使用する」として運用されていることが専らである。
- ^ Cではオーバーフロー発生時の動作は未定義。整数が2の補数でオーバーフローした値が負と扱われる場合、2038年1月19日3時14分7秒の次は1901年12月13日20時45分52秒となる。
- ^ 計算機による計算においては、このような一見して何の変哲もない式によるバグは入力数値がある程度大きくならないと露呈しにくく、この問題に限らず普遍的なものであり、一般に注意を要する。
- ^ 9,223,372,036,854,775,807 秒 ÷ (602 × 24 × 365.2425) ≒ 2.9228×1011年 ≒ 3000億年。これは太陽系の寿命よりもはるかに長い(太陽の白色矮星化は西暦68億年ごろ)。
出典
[編集]- ^ "The range and precision of times representable in clock_t and time_t are implementation-defined.", ISO/IEC 9899 7.23.1.4
- ^ 大和田尚孝 (2004年2月2日). “コンピュータの“西暦2038年問題”発生、早くも日本を揺るがす”. 日経コンピュータ
- ^ CHANGE-MAKERS. “2025年問題の次は2038年問題!コンピュータの暦問題を探る(後編)”. 2018年11月20日閲覧。
- ^ NSDate - Foundation | Apple Developer Documentation
- ^ Date Representations
- ^ NSTimeInterval | Apple Developer Documentation
- ^ 32 ビット App と macOS High Sierra 10.13.4 以降の互換性 - Apple サポート
- ^ FILETIME (minwinbase.h) - Win32 apps | Microsoft Docs
- ^ システム日付が 2038 年以降に設定されていると、Windows XP のセットアップが途中で停止する場合がある, Internet Archive
- ^ Another look at the year 2038 problem | Microsoft Docs
- ^ Time Management | Microsoft Docs
- ^ “「西暦2038年問題」でトラブル相次ぐ”. 日経コンピュータ. (2004年4月1日)