閒聊:謠傳量產 150 歲人瑞的 1875 年出生日期是怎麼來的?
| | 1 | |
馬斯克前幾天批評美國社會安全局(SSA)的資料庫大有問題,資料裡包含 134 萬位 150 歲人瑞,還有不少人超過 160、200 歲,甚至 360 歲的人類奇蹟。
參考新聞:
【補充】對照來源數據,新聞有誤導之嫌,1875 年不應為本案例焦點,是個假議題。
這種情況程式老鳥們應該已見怪不怪,不就經典的「資料很髒」案例,在江湖走跳早晚要碰到。
但其中 150 歲有一百多萬筆! 是怎麼冒出來的。依據某雜誌的說法:來源
SSA 使用的古老 COBOL 系統,在遇到出生日期缺失時預設會以 1875/5/20 取代,因為該日是國際標準度量衡「米制公約」(Metre Convention)的簽署日期。
而另一篇報導,則有專家說是 2004 年有設定標準,所有空白字段的日期會被編譯器預設為 1875 年。
許多系統的時間不是從西元 0 年開始,像 JavaScript/UNIX 的日期從 1970 開始, Excel 為 1900,我玩電腦玩這麼久,從 1875 起算還真是第一次看到。
2025-02-22 更新
研究了一下,最早 COBOL 根本沒有日期型別,多半是用六位數字表示(所以才惹出了 Y2K 千禧年危機),而怎麼處理空值也全憑程式設計師發揮創意。
網路上有網友自稱資深 COBOL 程式設計師,言之鑿鑿說確有用 1875 表示空值一事,但底下不少人持反對意見。截至目前為止,並沒有任何人找出一刀斃命的證據能證明當年 COBOL 有所謂用 1875 取代空值的慣例。(可能時間真的太久遠了,證據沒能數位化難以搜尋)
之所以傳出有所謂「標準」,很有可能是 2004 年 ISO 8601 標準曾定義 1875 年 5 月 20 日(米制公約 簽署日期)這個參考日期,但後來在 ISO 8601-1:2019 中被忽略來源。只是這件事發生於 2004,以此主張幾十年前的 COBOL 也是用它當基準過於薄弱。
在 StackExchange 的這串討論是我找到含金量的資訊來源,底下一堆用過 Cobol-85、Cobol-74,甚至 Cobol-68 的前輩留言,其中還有令人大開眼界的上古程序員日常:
1975 年為保險公司處理資料,需從 400 萬張打孔卡片讀取資料。紀錄橫跨了三個世紀:從 1800 年代後期的兒童人壽保險、1900 年代的現行保單以及可能延續到 2080 年的新壽險保單,所有年份都以兩位數字表示,當時必須使用 COBOL-68 驗證和轉換這些複雜資料。
照片來源:The IBM punched card
討論中的這則評論提出一個有趣且有點道理的猜想:
- 美國社會保險是在 1935 年引入的,必須要繳保費至少 10 年後才能領取,故第一批定期領取社會保險金的受益人是在 1945 年滿 65 歲,也就是 1880 年出生的那一批。再加上5年的緩衝期,可以抓最早可記錄的生日是 1875 年。
- 預設 1875-05-20 並不是因為這天是米制條約簽署的日子,或者某個「老程序員」的智慧,而可能是基於程式效率的考量。
- 1930 到 1950 的電腦還在打孔卡片的年代,每個字元的成本比現在高多了(更多的紙卡跟打孔動作),故日期用 8 個字元儲存太過奢侈(比吃布丁不舔蓋子還浪費)。當時大多數商業應用程序將日期存成 5 個字元。3 位個表示天(1 ~ 366)兩位表示年份。
- 生日欄位設計成 3 位年份加 3 位日期(1 ~ 366),年份以 1885 為 0 向上加,三位數 0 ~ 999 可以涵蓋 1885 - 2884, 且沒有 Y2K 問題。
- 若採用以上設計時,若欄位為 0,反推的日期就是 1885。
看似有理,但這個說法有個疑點,日期有效值 1 ~ 366,空值的年份為 0 會誤判成 1885,但日期也為 0 便可精準識別出資料無效,為何還會搞出這種烏龍?一種可能是資料在多次搬移轉換過程,混雜了思慮不周的換算規則,最終資料細節遺失而原始資料已不復存在,再也無法溯源校正。
不過,一切都是局外人的猜想,事實的真相只有 SSA 有能力找出答案。但在被馬斯克瘋狂 Diss 的當下,我想 SSA 此刻也沒啥閒情逸致考古挖真相吧,哈。 XD
Comments
# by GregYu
難怪, 根據另一個 [傳聞], 美國 還存在一個山洞, 用來保存 [紙本記錄], 該不會就是用來 [佐證] 的吧!?