削除された内容 追加された内容
タグ: モバイル編集 モバイルウェブ編集
→‎類似する年問題: 感想的文言の除去
 
(37人の利用者による、間の48版が非表示)
1行目:
{{出典の明記|date=2015年7月}}
'''2038年問題'''(にせんさんじゅうはちねんもんだい)は、[[2038年]][[1月19日]]3時14分7秒([[協定世界時|UTC]]、以下同様)を過ぎると、[[コンピュータ]]が誤する可能性があるとされる[[年問題]]。
 
== 経緯 ==
[[ファイル:Year 2038 problem.gif|right|400pxupright=2.0|thumb|上から、2進・十進・問題のある時刻・正しい時刻。([[GIFアニメ]])3時14分7秒を超えたところで負の値となり、時刻に狂いが生じる恐れがある。]]
コンピュータおよび[[プログラム (コンピュータ)|コンピュータプログラム]]における[[時刻]]の表現として「[[UNIX時間]]」《[[協定世界時]]における1970年1月1日0時0分0秒からの経過秒数<ref>{{efn|「ただし、うるう秒を無視して現在時刻から逆算した値を使用する」として運用されていることが専らである。</ref>}}》を使用しているコンピュータ等のシステムがある。この起点の時刻は、最初に[[UNIX]]にそのような機能が実装された時にキリがよかった過去の時刻であり、たまたまそう決めたというだけのものに過ぎない
 
[[UNIX]]およびUNIX派生の[[オペレーティングシステム]] (OS) における基幹[[ソフトウェアコンポーネント|ソフトウェア部品]]の多くは[[C言語]]で書かれているが、前述の経過秒数を表現する型は、現在の標準では、「[[time_t]]型」である。[[C言語]]の標準である「ISO/IEC 9899:1999」では、<code>time_t</code>型の範囲や精度はいずれも実装定義としている<ref>"The range and precision of times representable in clock_t and time_t are implementation-defined.", ISO/IEC 9899 7.23.1.4</ref>。UNIXの標準 ([[POSIX]]) には「shall be integer or real-floating types.」とのみ記述があり、ビット幅ないしおよび値の範囲については何らの定めも無い。
 
伝統的な実装では<code>time_t</code><code>int</code>または<code>long</code>の[[typedef]]による型エイリアス(別名)とし、そのintは符号き[[32ビット]]整数型であった。このため最大値は (2<sup>31</sup> − 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秒、[[閏秒]]は考慮していない)を過ぎると、この値が[[算術オーバーフロー|オーバーフロー]]し{{efn|Cではオーバーフロー発生時の動作は未定義。整数が[[2の補数]]でオーバーフローした値が[[負の整数|負]]と扱われる<ref>時刻の場合、2038年1月19日3時14分7秒の次は'''1901年12月13日20時45分52秒'''となる。</ref>ため}}もし時刻を正しく扱えていることを前提としたコードがあれば、誤する。
 
ある実装における <code>time_t </code>の型を変更することだけであれば、プログラム中のたった1箇所 ([[typedef]]) を書き換えるだけであるが、実際の運用では、アプリケーションプログラムにおける時刻の扱い全てが正しくある必要がある。また、すでにあるデータ構造中で32ビット固定長として割り当てられていれば、問題が発生する。たとえば、Linuxの[[ファイルシステム]]を例に挙げであと、[[ext2]][[ext3]][[ReiserFS]]の[[タイムスタンプ]]は同日付までしか対応していない。
 
この期日以前でも[[プログラム (コンピュータ)|プログラム]]で内部的にこの制限を超えた時刻データを扱おうとすれば同様のエラーが発生するため、たとえばちょうど半分を経過した2004年1月11日にはすでに[[現金自動預け払い機|ATM]]の誤といったトラブルが発生した<ref>{{Cite news|author=大和田尚孝「[http|url=https://itproxtech.nikkeibpnikkei.co.jpcom/it/free/NC/NEWS/20040202/139212/ |title=コンピュータの“西暦2038年問題”発生、早くも日本を揺るがす]」|publisher=[[日経コンピュータ]]|date=2004年2月2日-02-02}}</ref>。この事例ではプログラム中のある時刻と別の時刻の中間の時刻を求めるような処理で、相加[[平均]]を単純に求める <math>(t_1 + t_2) / 2</math> のような式を利用していたものとみられる{{efn|計算機による計算におけるいては、このような一見して何の変哲もない式によるバグは入力数値がある程度大きくならないと露呈しにくいバグはく、この問題に限らず普遍的なものであり、一般に注意を要する。}}。他にも顕在化していないトラブルが今後表面化するという可能性はあり得る。
 
2000年問題はアプリケーションレベルでの修正が可能であったが、この問題は現在普及しているC言語[[処理系]]やOSのAPIといったシステムの深い層に潜む問題であるため、[[2000年問題]]より深刻であるという指摘もある<ref name="change-makers.jp/technology/11351">{{Cite web|和書|title=2025年問題の次は2038年問題!コンピュータの暦問題を探る(後編)|author=CHANGE-MAKERS|url=https://www.change-makers.jp/technology/11351|access-date=2018-11-20}}</ref>。
以下のような理由により、2000年問題より深刻であるという指摘もある{{誰2|date=2015年7月}}。
*[[2000年問題]]はアプリケーションレベルでの修正が可能であったが、この問題は現在普及しているC言語処理系やOSのAPIといったシステムの深いレイヤに潜む問題である。
*「32ビットの符号付2進表現におけるラップアラウンド」という理由を理解するには、ある程度の専門知識を必要とするので、一般大衆、経営者、政治家などの理解と関心を得にくい可能性がある。
*2000年問題のように暦年の変わり目というキリのよいときに地域の標準時に応じて順次に問題の時刻が世界を巡るのではなく、ごく中途半端な時刻に世界同時に一斉に問題の時刻が訪れるので、もし問題が生じた場合は対応するための人的資源の確保がより困難となる可能性がある。
 
== 対策 ==
対策としては、<code>time_t</code>型を符号き64ビット整数型(一般には'''<code>long long int</code>型''')にするという方法がある。符号き64ビット整数型の場合、上限は'''9,223,372,036,854,775,807{{val|9223372036854775807|fmt=commas}}''' (({{2<sup>^|63</sup>}}1) 1)である。これを年数に変換するとおよそ西暦3000億年<ref>9,223,372,036,854,775,807{{efn|{{val|9223372036854775807|fmt=commas|u=}} ÷ (60<sup>2</sup> × 24 × 365.2425) ≒ 2.9228{{Eval|112.9228e11}}年 ≒ 3000億年。これは[[太陽系]]の寿命よりもはるかに長い([[太陽]]の[[白色矮星]]化は西暦68億年ごろ)。</ref>}}まで使用できるので、事実上問題が発生することはない。最近64ビット版の[[オペレーティングシステム]]や[[処理系]]では、<code>time_t</code>型は符号き64ビット整数型で表されるようになってきている。UNIXベースのOSでは、64ビット版で<code>time_t</code>も併せて64ビット化されることが多い
 
また、何らかの事情により<code>time_t</code>を64ビット化できない環境に対しては、<code>time_t</code>を符号し32ビット整数型(一般的には'''<code>unsigned long int</code>型''')にするという回避策が使われることもある。この場合、上限は'''4,294,967,295{{val|4294967295|fmt=commas}}''' (({{2<sup>^|32</sup>}}1) 1)となり、[[2106年]]2月7日6時28分15秒(閏秒を考慮しない場合)まで表現可能になる。従って2038年問題は回避できるが、結局2106年には問題が発生するため、あくまで64ビット化が困難な環境に限って適用すべき方法とされる。
 
[[macOS]](OS X)([[Mac OS X]] 10.0) では<code>NSDate</code>クラスにて[[協定世界時]]の2001年1月1日0時丁度ちょうどをエポックタイムに更として刷新したため<ref>[https://developer.apple.com/reference/foundation/nsdate?language=objc NSDate - Foundation | Apple Developer Documentation]</ref><ref>[https://developer.apple.com/library/prerelease/content/documentation/CoreFoundation/Conceptual/CFDatesAndTimes/Concepts/DataReps.html#//apple_ref/doc/uid/20001139-CJBEJBHH Date Representations]</ref>、また経過時間の内部表現として[[倍精度浮動小数点数]]を用いるようになったため<ref>[https://developer.apple.com/documentation/foundation/nstimeinterval NSTimeInterval | Apple Developer Documentation]</ref>、これを使用している限り、2038年については問題を回避できる。なお、[[macOS Mojave]]は32ビットアプリケーションを動作させることのできる最後のバージョンとなり、[[macOS Catalina]]では起動することができなくなった<ref>[https://support.apple.com/ja-jp/HT208436 32 ビット App と macOS High Sierra 10.13.4 以降の互換性 - Apple サポート]</ref>
 
32ビット版の[[Microsoft Windows]] (Win32) では内部時刻の表現に64ビット化された<code>FILETIME</code>構造体<ref>[https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime FILETIME (minwinbase.h) - Win32 apps | Microsoft Docs]</ref>を使っており、<code>time_t</code>を使っているわけではない。そのため、Windows OS側に関しては、旧OSに関する一部のケースを除き<ref>[https://web.archive.org/web/20060626085939/http://support.microsoft.com/kb/436249/JA/ システム日付が 2038 年以降に設定されていると、Windows XP のセットアップが途中で停止する場合がある], [[Internet Archive]]</ref><!-- Windows XP SP3 では解消されているのかもしれないが、未確認。 -->、32ビット版であっても2038年問題は発生しない<ref>[https://docs.microsoft.com/en-us/archive/blogs/mthree/another-look-at-the-year-2038-problem Another look at the year 2038 problem | Microsoft Docs]</ref>。ただし、Microsoft C/C++ (MS-C) および古いバージョンの[[Microsoft Visual C++]] (MSVC) においては、<code>time_t</code>は32ビットの<code>long int</code>を使って定義されていたため、これらの古い処理系のC/C++ランタイムライブラリ (CRT) を利用して構築された[[アプリケーションソフトウェア]]や[[DLL]]などは、2038年問題を抱えていることになる。[[x64]]アーキテクチャの64ビット版Windows OS上では[[WOW64]]サブシステムにより[[x86]]アーキテクチャ向けに構築された32ビットアプリケーションも動作させることができるが、古い32ビットアプリケーションにおける2038年問題は、たとえWindows OSを64ビット版に入れ替えたとしても回避することはできない。[[Microsoft Visual C++]] 2005以降では、既定で<code>time_t</code>は<code>__time64_t</code>と等しく<ref>[https://docs.microsoft.com/en-us/cpp/c-runtime-library/time-management Time Management | Microsoft Docs]</ref>、32ビットアプリケーションであっても<code>time_t</code>は64ビット化されるため、古いアプリケーションを新しい処理系およびランタイムで構築し直せば2038年問題を回避できる。
 
== 関連した問題 ==
*時刻aと時刻bのちょうど中間の時刻を求めたい時、それぞれのUnixタイムをTaとTbとして、(Ta+Tb)/2 のように計算すると、2038年問題の半分以降が経過していればTa+Tbの計算で[[算術オーバーフロー|オーバーフロー]]し、間違った結果なる。これは1,073,741,824{{val|1073741824|fmt=commas|u=}}目であり、2004年1月10日13時37分4秒以降がこの場合に相当する(実際に2004年1月10日乃至あるいは11日に、そのようにして起きたも事例思わ推察されるトラブルの報告があった<ref>
「[http{{Cite news|url=https://itpro.nikkeibpxtech.conikkei.jpcom/it/members/NC/ITARTICLE/20040325/1// |title=「西暦2038年問題」でトラブル相次ぐ]」|publisher=[[日経コンピュータ]]|author=|date=2004年4月1日-04-01}}</ref> この問題を回避するためには、計算方法を工夫する必要がある。例えば、時刻の中間を求める際に、オーバーフローを避けるために次のような方法が考えらる:
*# '''時刻の差を計算する''': まず、時刻bから時刻aを引いて、その差を求める。
*[[2001年9月9日問題]]は、2001年9月9日にtime_t型の値が999,999,999秒から1,000,000,000秒と桁が増えることに伴う問題。time_t型の値を文字列(辞書順)でソートしていたことで、「999,999,999 > 1,000,000,000」と判断され、項目の新旧が正しく判断されない問題(新しく作られた項目が表示されない、古いものとみなされ削除されるなど)が発生した。
*# '''差の半分を求める''': 求めた差を2で割る。
*[[Network Time Protocol|NTP]]など、1900年1月1日からの積算秒数で時間を表現するシステムもあり、符号なし32ビットの値が[[2036年]][[2月7日]]6時28分15秒 (UTC) を超えるとオーバーフローすることによって問題が発生する(→[[Network Time Protocol#2036年問題|2036年問題]])。[[Simple Network Time Protocol|SNTPv4]]を定めたRFC 4330には、最上位ビットが0の場合は時刻が2036年から2104年の間であるとみなして、2036年2月7日6時28分16秒 (UTC) を起点として計算することで2036年問題を回避する方法が書かれている。
*# '''時刻aに加える''': 最後に、時刻aに差の半分を加えることで、中間の時刻を求める。 この方法を数式で表すと、次のようになる: 中間時刻=''Ta''​+(''Tb''​−''Ta''​)​/2
 
== 類似する年問題 ==
 
*[[2001年9月9日問題]]は、2001年9月9日にtime_t型の値が999,999,9999億秒から1,000,000,00010億秒と桁が増えることに伴う問題。time_t型の値を文字列(辞書順)でソートしていたことで、「999,999,9999億 > 1,000,000,00010億」と判断され、項目の新旧が正しく判断されない問題(ず、新しく作られた項目が表示されない、古いものとみなされ削除されるなどの問題が発生した。
*[[Network Time Protocol|NTP]]など、1900年1月1日からの積算秒数で時間を表現するシステムもあり、符号なし32ビットの値が[[2036年]][[2月7日]]6時28分15秒 (UTC) を超えるとオーバーフローすることによって問題が発生する(→[[Network Time Protocol#2036年問題|2036年問題]])。[[Simple Network Time Protocol|SNTPv4]]を定めたRFC<nowiki/>{{IETF RFC|4330}}<nowiki/>には、最上位ビットが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年を閏年と誤認識する可能性がある。この問題を回避するためには、システムの閏年計算ロジックを修正する必要がある。
 
== 脚注 ==
{{脚注ヘルプ}}
=== 注釈 ===
{{reflist}}
{{Notelist}}
=== 出典 ===
{{Reflist}}
 
== 関連項目 ==
42 ⟶ 55行目:
 
== 外部リンク ==
*[http://sunpillar.jf.land.to/bekkan/javascript/2038.shtml#TIMER 2038年問題へのカウントダウン]{{Ja icon}}
*[http://support.microsoft.com/kb/436249/JA/ システム日付が2038年以降に設定されていると、Windows XPのセットアップが途中で停止する場合がある]
 
{{年問題}}
{{DEFAULTSORT:2038ねんもんたい}}
 
{{DEFAULTSORT:2038ねんもんたい}}
[[Category:コンピュータ]]
[[Category:コンピューター問題2038年]]
[[Category:UNIX]]
[[Category:コンピュータ史]]
[[Category:年問題日時の表現法に起因するバグ|2038]]
[[Category:情報社会未来問題]]
[[Category:2038年]]