Unix時(shí)間并沒有出現(xiàn)錯(cuò)誤
1234567890是個(gè)節(jié)日, 一秒鐘的節(jié)日. 它不是問題, 不是錯(cuò)誤, 不是BUG. 我們?nèi)祟愂褂玫挠?jì)時(shí)系統(tǒng)是相當(dāng)復(fù)雜的:秒是基本單位, 60秒為1分鐘, 60分鐘為1小時(shí), 24小時(shí)是一天......如果計(jì)算機(jī)也使用相同的方式來計(jì)時(shí), 那顯然就要用多個(gè)變量來分別存放年月日時(shí)分秒, 不停的進(jìn)行進(jìn)位運(yùn)算, 而且還要處理偶爾的閏年和閏秒以及協(xié)調(diào)不同的時(shí)區(qū). 基于"追求簡(jiǎn)單"的設(shè)計(jì)理念, UNIX在內(nèi)部采用了一種最簡(jiǎn)單的計(jì)時(shí)方式:
計(jì)算從UNIX誕生[注釋1]的UTC時(shí)間1970年1月1日0時(shí)0分0秒起, 流逝的秒數(shù). UTC時(shí)間1970年1月1日0時(shí)0分0秒就是UNIX時(shí)間0, UTC時(shí)間1970年1月2日0時(shí)0分0秒就是UNIX時(shí)間86400. 這個(gè)計(jì)時(shí)系統(tǒng)被所有的UNIX和UNIX-like系統(tǒng)繼承了下來, 而且影響了許多非UNIX系統(tǒng). POSIX標(biāo)準(zhǔn)推出后, 這個(gè)時(shí)間也被稱為POSIX時(shí)間.
UNIX時(shí)間錯(cuò)誤是誤解
可能是因?yàn)槿祟愂且环N需要精神上的刺激的生物吧, 各種歷法中都存在著各種擁有不同意義的節(jié)日. 其中, 很多節(jié)日僅僅由于日期的特殊性就被賦予了意義, 例如公歷1月1日的新年, 11月11日的光棍節(jié),愛好節(jié)日的人們也沒有放過UNIX時(shí)間. UTC時(shí)間2001年9月9日1時(shí)46分40秒, UNIX時(shí)間迎來了第一個(gè)"億禧年"(Billennium)[注釋2], 1000000000. UTC時(shí)間2005年3月18日1時(shí)58分31秒則是UNIX時(shí)間的光棍節(jié), 1111111111. 剛剛過去的1234567890, 對(duì)應(yīng)公歷的UTC2009年2月13日23時(shí)31分30秒, 對(duì)東一區(qū)以東的時(shí)區(qū)來說是2月14日情人節(jié), 以西的時(shí)區(qū)來說則剛好落在黑色星期五. 傳統(tǒng)上認(rèn)為黑色星五不吉利的西方媒體, 針對(duì)此事進(jìn)行了玩笑性的報(bào)道, 結(jié)果被一些居住在其他時(shí)區(qū)的人們誤讀成了"UNIX時(shí)間錯(cuò)誤"。
丹麥哥本哈根的丹麥UNIX用戶群組織慶祝UNIX"億禧年" 圖為當(dāng)時(shí)所用的倒計(jì)時(shí)公告牌
無獨(dú)有偶, 2012年7月13日也是一個(gè)黑色星期五, 而那天的UTC時(shí)間11時(shí)1分20秒對(duì)應(yīng)著UNIX時(shí)間0x50000000(十六進(jìn)制, 十進(jìn)制值是1342177280). 不知到了那個(gè)時(shí)候, 會(huì)不會(huì)再次有人把它誤解為又一次的UNIX時(shí)間錯(cuò)誤?
2038年的問題才是混亂
UTC時(shí)間2033年5月18日3時(shí)33分20秒, 是UNIX時(shí)間的第二個(gè)"億禧年"(Billenniumm), 即2000000000. 然而, 第三個(gè)"億禧年"(Billennium)則不會(huì)毫無障礙的來臨, 在那之前, 人們先得解決正在變得著名的2038年問題. 和本世紀(jì)初的千年蟲(Y2K Bug)問題類似, 2038年問題(Y2K38 BUG)更隱蔽, 而且更難解決. 我們知道計(jì)算機(jī)內(nèi)部的一切都是二進(jìn)制的, 也就是說1234567890在32位系統(tǒng)的內(nèi)存里實(shí)際上是01001001 10010110 00000010 11010010. 這串32位二進(jìn)制數(shù)中, 最高位被用來表示正負(fù)符號(hào), 0代表整數(shù), 1代表負(fù)數(shù), 所以它能表示的最大數(shù)字就是01111111 11111111 11111111 11111111, 即214748367, 對(duì)應(yīng)公歷的UTC時(shí)間2038年1月19日3時(shí)14分7秒. 到這天的凌晨3時(shí)14分8秒, UNIX時(shí)間會(huì)溢出并變成10000000 00000000 00000000 00000000(十進(jìn)制值-214748368), 也就是UTC時(shí)間1901年12月13日20時(shí)45分52秒, 引起和千年蟲類似的混亂.
2038年問題的動(dòng)畫演示
或許64位可以解決這個(gè)問題
2038年問題不僅比千年蟲更隱蔽, 而且它的原因也更接近系統(tǒng)底層. 要解決這個(gè)問題, 最簡(jiǎn)單的方式是擴(kuò)展UNIX時(shí)間的長度, 用64位數(shù)字來表示它. 64位二進(jìn)制數(shù)的實(shí)際可用位數(shù)是63位, 最大表示到公歷的UTC時(shí)間292277026596年12月4日. 如果那個(gè)時(shí)候人類文明還存在的話, 公元紀(jì)年很可能已經(jīng)因?yàn)樘y用而被拋棄了. 理想的情況是到2038年, 64位系統(tǒng)已經(jīng)成為主流, 從而避免特意去修正這個(gè)問題所需要的大量開銷. 否則, 人們就必須把新的64位時(shí)間拆分成兩部分并分別保存在兩個(gè)變量里, 這是一個(gè)麻煩而且效率低下的選擇.
[注釋1]: 就像很多其他的節(jié)日一樣, 把UNIX的誕生日選在這天只是出于方便. 實(shí)際上, 最早的運(yùn)行在PDP-7上的UNIX在1969年就已經(jīng)完成了.
[注釋2]: Billennium實(shí)際上是"十億禧年", 但是這樣聽起來很奇怪, 所以我用"億禧年"作為暫用名.
【編輯推薦】