2000年問題

<image>

2000年問題（Year 2000 Problem，別稱Millennium Bug或Year 2000 Bug，簡稱Y2K），中國大陸及香港常稱千年蟲問題，台灣則稱千禧蟲危機，是一個電腦程式在日期表達上的設計缺陷。許多早期設計的電腦程式為節省存儲空間而普遍採用以6位數字存儲日期，只取4位年份數字中的後2位數字用於表示年份的做法。由於表示世紀的前兩位年份數字被剔除，受此影響的電腦無法正確區分不同世紀的同一兩位數年份，最終導致其在處理跨世紀信息時日期識別紊亂，並在日期比較、排序、期限計算、排程或數據交換等操作中產生錯誤，進而影響相關系統的運行。

使用6位數日期的做法普遍於20世紀中期的程序設計中，這些程序設計時並未設想長期使用，也鮮有處理涉及前兩位年份變更的長跨度日期資訊需求，隨著這些早期設計發展為行業標準，這種帶有缺陷的日期表示法也被保留下來。直到21世紀和2000年臨近，而6位數日期正會導致電腦在前兩位年份數由19跨越至20時出現問題，該缺陷由此被廣泛稱為2000年問題。

自20世紀90年代開始，2000年問題逐漸透過媒體的傳播引起了人們的關注，同時也引發了大眾恐慌。政府部門、軍隊、基礎設施與許多重要行業直到那時都還使用著老舊的資訊系統。一旦工作在這些領域的電腦出現問題，將可能導致從停水、斷電，銀行癱瘓到核電廠事故和軍械失控等一系列災難性的後果。針對該問題進行的全球性大規模修復行動隨之開始，全世界為修復2000年問題前後累計投入了約3080億美元，而在持續數年的修復之後，該問題最終得到了有效解決，沒有在新千年到來之際大規模爆發。

## 問題起因

發布於1959年的IBM 1401的磁芯存儲器模塊，其容量僅為4KB的版本即要價20100美元，換算到2015年時即為162000美元。

雖然2000年問題的中文別稱「千年蟲」常使人將其誤認為電腦病毒，但實際上它只是一個電腦程式在日期表示方面的缺陷，並非惡意編寫的電腦病毒。該問題起始於20世紀50年代到60年代，那時電腦的存儲器價格極為昂貴，並且容量很小，早期的磁芯存儲器價格平均為每比特1美元，而在同一時期，一塊大小僅為1MB的硬碟價格即為761,000美元。且當時的電腦仍舊採用打孔卡來存儲和輸入數據，編寫好的程序本身就要被存儲到打孔卡上，然後再被機器讀取並編譯，有時候向程序輸入數據也需要使用打孔卡。一個最常見的IBM打孔卡只有80列寬，能儲存的數據也極其有限。因此，程式設計師在編寫程序時需要儘可能的節省存儲空間，以最大程度的降低存儲成本。因此，當時的程式設計師普遍在編寫程序時採用六位數來存儲日期，只取四位數年份中的後兩位來表示年份，例如，1976年10月23日就會被簡短的存儲為23/10/76或10/23/76。對當時的情況來說，六位數日期表示法有很大的作用，它能夠減小程序的記憶體需求，並減少一個程序所要占用的打孔卡卡數。這種做法沿襲自更早之前的穿孔制表機時代，當時的操作員就已經在打孔卡上慣用六位日期來節省時間和空間。在要處理大量日期數據時，六位數日期表示法還能發揮更大的作用。例如，一間擁有一千萬客戶，每個客戶每天交易三次的銀行若要在電腦中存儲一周所有客戶的交易時間，只取兩位數年份能為這家銀行省下60兆字節的存儲空間。

後來，隨著科技的發展，到了20世紀70年代，磁芯存儲器的價格逐漸下降到僅為每比特1美分。而同時，具有同樣價格，但尺寸更小且更便於使用的DRAM也開始逐步替代了磁芯存儲器，打孔卡亦被逐漸淘汰，存儲技術的進步和其價格的大幅降低使得存儲空間不再是一個緊迫的問題。在程序中使用六位數日期的必要性也越來越低，但其並沒有就此退出歷史舞台，儘管存儲介質歷經數次變遷，但其中的數據結構通常變化不大。出於程式設計師們的習慣，以及為了保持向上兼容，六位數日期表示法就被一直沿用下來。即使當時已經有人提出過在這一日期表示法下潛藏的問題，但當時的程式設計師普遍都認為自己編寫的程序不可能被持續使用到新千年，並沒有理會這些警告。

IBM於1964年推出的大型機System/360是世界上首款實現多規格機型相互兼容的電腦，它定義了包括直到今日都仍在使用的單字節8比特長度在內的多項電腦行業標準，對之後多年的電腦設計都產生了深遠的影響，而IBM在這套系統中繼續沿用了六位數日期表示法；1967年，美國政府要求美國國家標準局統一電腦日期資訊處理標準，以結束圍繞該問題多年的爭論，出於對存儲空間成本的考量，使用有大量電腦的美國國防部在標準局的意見徵集中強烈要求使用兩位數年份，迫於國防部的壓力，美國國家標準局宣布，從1970年1月1日開始，美國聯邦機構將優先採用兩位數年份來標示日期。隨後，美國國家標準局將六位數日期表示法寫入了1968年11月發布的聯邦資訊處理標準4號出版物《Calendar Date》中，在這份標準給出的示例中，1967年1月15日應當被編碼為「670115」。不過，這份標準亦有規定，若日期資訊跨度超過一個世紀，則可將年份位數擴展至四位；與之相對的，若日期資訊跨度不超過十年，則年份位數還能被縮短為一位。

六位數日期表示法雖然的確在節省存儲空間上發揮出了作用，但這種模糊的表示法也為未來埋下了隱患。人們在日常生活中為了方便有時也會只用兩位數簡稱一個年份，但電腦和人類的區別在於，人類擁有能夠理解並補全前兩位年份數字的能力，但電腦沒有。它們只會讀取被實際寫出來的後兩位年份，無法自行變更沒被實際寫出來的前兩位年份數字。這就導致了一個問題：在六位數日期下，2000年1月1日將會被轉為01/01/00，然而，由於前兩位年份沒被實際寫出來，也就無法進行變更，電腦就會繼續將前兩位默認為「19」，如此一來，就使得電腦會將2000年誤認為1900年，認為被縮寫為「00」的2000年要早於被縮寫為「99」的1999年。這會導致電腦在執行任何涉及到日期的任務時出錯，甚至引發崩潰。例如，醫生要使用一台電腦為一位出生在2000年的嬰兒計算要為他使用的藥物劑量，若這台電腦仍舊使用六位數日期表示法，其就會將這位嬰兒誤認為是一位出生在1900年的百歲老人，並對醫生給出一個適用於老年人的藥物劑量，但這個劑量對新生兒來說可能會是致命的。若不對該問題加以修復，諸如此類的故障會在2000年到來時在全球爆發，影響到所有依賴這些有缺陷的電腦運作的基礎設施和軍政機關，導致停電停水、醫療癱瘓、通信終止到飛彈誤射等一系列災難性的後果。

此外，2000年問題也會在除2000年1月1日以外的日期造成影響，並且也不止會導致電腦誤判2000年及之後的年份。因為問題的根源是電腦無法變更前兩位的年份數字，其也會導致電腦錯誤判定1900年之前的年份；而一些使用數字99或9999作為文檔終止標記或停止代碼，且仍舊採用兩位數年份表示法的電腦則可能會在1999年9月9日出現故障；另外，一些電腦由於採用了不正確的閏年識別演算法，致使其無法將2000年正確識別為閏年，從而導致它們在2000年2月29日、3月1日、12月31日、2001年1月1日出現故障，該問題也在2000年問題的範疇之內。其它會致使2000年問題的原因還包括將「19」硬編碼到軟體子程序中、採用可能會致使存儲寄存器溢出的日期數據類型。

## 修複方式

對2000年問題最直接，也最徹底的修復方式就是直接將六位日期糾正為完整的八位日期。但這種方式的成本通常也是最高的，因為要完全糾正所有引用和使用了兩位數年份的程序，以及所有引用了日期數據的資料庫，確保整套系統內所有程序都被正確轉換到了新日期格式，因為未經修改的舊程序可能會直接訪問到日期欄位的內部結構，從而又再度破壞掉修正後的系統；此外還需要調整所有數據欄位的位置引用，以及所有包含日期數據的記錄的格式；重新格式化並重寫包括過往數據文件在內的所有數據文件，同時還可能需要修改各個系統之間的消息格式。

為了降低修復所需的時間和人力成本，另有一些更為簡便的修複方式被廣泛使用：

日期窗口化：保留原始的兩位數年份寫法，在此基礎上設定一個年份數字的「基準點」，例如40。並使電腦將高於這個基準點的數字識別為以「19」開頭的年份，例如「89」就會被這套系統辨識為「1989」。而低於這個基準點的數字則會被識別為以「20」開頭的年份，例如「15」就會被辨識為「2015」。從而達到使電腦順利度過2000年，維持正常年份更迭的目的。由於之前的兩位數年份寫法被保留，程式設計師只需要基於這個方式找到找到系統內所有涉及日期的引用，並適當調整它們的計算方式即可，故而相較於直接補全日期減少了很多工作量和修復成本，也是最為常用的2000年問題修複方式。但這種方式並非永久性的解決方案，一旦電腦運作至超過基準點年份時，便會再次出現問題，且經這種方式處理的電腦也沒有辦法處理任何時間跨度超過100年的數據，應用這種修複方式的初衷只是期望可使電腦延壽至下一次系統更迭。在實際應用上，基準點是視具體情況而定的，例如，對某間成立於1928年的公司來說，要修改他們用來處理髮票數據的系統，就最好將「25」應用為基準點。還有一些程式設計師在此基礎上拓展出了「浮動窗口化（sliding windows）」的修復技術，可使基準點隨時間而變動。

編碼世紀信息：同樣不改變原有的日期欄位長度，在此基礎上改變電腦的日期編碼邏輯，將世紀更迭的資訊存入6個字符中。例如，在每個字符均占8個比特的情況下，6位字符在電腦底層中就是48個比特。如此一來，就可以將從儒略日起點（公元前4713年1月1日）到現今為止經過的總日期數轉換成一個48位的純二進位數字存入電腦，就能使電腦存下非常遙遠的日期，順利過渡到2000年以後。這種修改方式具有多種實現策略，可行的實現還包括：將占兩個字節的兩位數年份作為一個整體的二進位數字存入完整的四位數年份、或是改變日期的表達方式，將六位數中的第一位用於代表世紀（如0=18開頭年份、1=19開頭年份、2=20開頭年份），之後的兩位繼續用於表示年份後二位數字，剩下的三位數就以「一年中的第X天」（001——366）的表達方式來表示日期。

倒轉系統時鐘：直接將系統時鐘倒轉28年，這個倒轉量可以保證在改變年份的情況下，星期和月份天數不變，且通常具有相同的閏年安排。之後再另於系統內部設置轉換層，在輸入和輸出數據時減去和加回28年，銜接系統日期和當前正確日期。如此一來，到2000年1月1日星期六時，電腦里仍然是不會使原有的六位數日期發生紊亂的1972年1月1日星期六。因為不涉及到對系統本身的修改，故這種修複方式適用於原始碼丟失或無法再次編譯的系統。此外，這種修複方式也只適用於每四年有一個閏年的時期。

## 修復行動

### 引起關注

<image>

1958年，當時在IBM工作的鮑勃·貝默在為耶穌基督後期聖徒教會編寫族譜記錄軟體時意識到了六位數日期寫法的缺陷，他在之後的數十年裡不斷在各處做出對六位數日期寫法缺陷的擔憂，並呼籲人們轉用標準的八位完整日期寫法，但都沒有起到很大的作用。其於1971年在《霍尼韋爾電腦期刊》上發表了一篇題為《What's the Date？》的文章，建議人們使用ISO 2014標準的規範日期寫法，這被認為是世界上第一篇公開發表的2000年問題警告文章，1979年，他再於雜誌《界面時代》發表另一篇文章《Time and the computer》，進一步深入探討了日期表示問題，他在這篇文章中也提到了2000年閏年問題，他還為COBOL添加了PICTURE子句，以允許程式設計師能夠在程序中使用四位數年份，此後他一直堅持向業界發出警告，直到他在1982年退休。

1993年，美國雜誌《Computerworld》刊登了一篇題為《Doomsday 2000》的文章，這篇文章的作者是加拿大程式設計師彼得·德·耶格，他在1977年於IBM上任操作員，在職期間，他意識到兩位數的年份寫法會為未來埋下隱患，並向管理層反饋了這一問題，但同樣也沒有起到作用。1993年，Computerworld的一名編輯在他進行了一場關於個人電腦的演講之後找到他，希望他能就這場演講的主題在Computerworld上發表一篇文章，不過彼得則提議要另寫一篇「真正的問題」，於是便以2000年問題為主題，撰寫了《Doomsday 2000》，這篇文章普遍被認為是引起電腦行業開始關注2000年問題的文章，彼得·德·耶格也因此被認為是將2000年問題帶入行業及大眾視野的人，此後也作為2000問題專家大量獲利。

1995年，IBM承認2000問題的存在，並開始向其客戶提供問題的解決服務、工具與支持，而微軟公司的聯合創始人與時任CEO比爾·蓋茨則在1996年7月表示2000年問題只是由「老化的大型機軟體」所導致的，並堅稱微軟的軟體不會受到2000年問題的影響，而後其又於1997年的一次行業峰會上表示對2000年問題的擔憂要歸咎於「喜歡講恐怖故事」的人，直到一年後，微軟才承認他們在2000年問題上「反應遲緩」。