計算機時間究竟是怎麼來的?程序員必看的時間知識!

微信搜索關注「水滴與銀彈」公衆號,第一時間獲取優質技術乾貨。7年資深後端研發,給你呈現不同的技術視角。python

你們好,我是 Kaito。程序員

這篇文章我想和你聊一聊「時間」這個話題。後端

時間老是在不經意間流逝,咱們在寫代碼時,也常常會調用「時間 API」,你有思考過這背後的原理嗎?服務器

關於時間的問題還有不少,例如:微信

  • 爲何計算機的時間有時候「走不許」?
  • 計算機到底是怎麼「自動校準」時間的?
  • 咱們常常看到的 UTC 時間,究竟是什麼?
  • 咱們在新聞上看到的「北京時間」,真的來自北京嗎?

這篇文章,咱們就來揭祕時間背後的祕密。markdown

這篇文章很是有意思,但願你能夠耐心讀完。網絡

時間爲何老是走「不許」?

你確定遇到過這樣的場景,家裏買了一個鐘錶,時間一長,就會發現它走得「不許」了。運維

又或者,一臺長時間不使用的電腦,它的時間也會發生誤差。oop

遇到這些狀況,你可能會不覺得然。時間不許,那咱們就「人工」調準它。學習

但你有沒有停下來想想,爲何它們的時間會越走越不許呢?

要回答這個問題其實不難,咱們只須要搞清楚,它們的時間是怎麼來的。

鐘錶和計算機內部都有一個叫作「晶體振盪器」的東西,給它加上電壓,它就會以固定的頻率振動。但這個振動頻率的「穩定性」,取決於它的製造工藝,以及外界環境的影響。

出於成本的考慮,鐘錶的製做工藝沒那麼高,因此它更容易有偏差。而電腦製造工藝雖然比較高,但它內部的晶體振盪器也會受到「溫度」變化帶來的影響,在工做過程當中,也會有產生偏差。

雖然它們的偏差很小,但日積月累下來,偏差就愈來愈明顯。

所以,咱們如今使用的計算機,都有「自動校準」時間的功能。可是如何校準呢?

如何校準時間?

很簡單,只要你把電腦連上了「網絡」,你會發現,它會自動與「網絡時間」保持同步。

可問題是,這個「網絡時間」哪兒來的?

我猜你大腦的第一反應是,每臺電腦確定配置了一個「時間服務器」,以後這臺電腦會與服務器定時同步,自動校準。

沒錯,確實是這樣,不光是電腦,咱們平時使用的手機、平板、智能手錶等電子設備,只要能鏈接網絡,都會自動同步網絡時間。

那繼續追問,這個「時間服務器」的時間就必定是準的嗎?

理論來說,它應該也是一臺計算機,難道它不會遇到咱們前面說的問題嗎?

此外,這個網絡時間到底是怎麼「同步」到咱們的電腦上的?

你可能會說,那確定是經過網絡數據包。

問題又來了,網絡傳輸數據也是有「延遲」的,同步服務器時間,不仍是存在偏差嗎?

環環相扣,像一個俄羅斯套娃,很難解釋清楚。

要想完全搞清楚這些問題,就要深刻到時間的「源頭」來尋找答案。

時間是怎麼來的?

時間是一個很是抽象的概念,多少年來,吸引着無數科學家、物理學家、甚至哲學家花費畢生精力去解釋時間的本質是什麼,從宇宙大爆炸到時空相對論,從黑洞到量子力學,都能看到關於時間這個問題的身影。

這裏咱們不探討高深莫測的學術知識,只把目光放聚焦在計算機這個很小的範疇內。但要想清楚解釋這個問題,也非並想的那麼簡單。

咱們從最簡單的開始提及。

想要知道時間是怎麼被定義的,首先要知道「天」是怎麼來的?

答案是:觀察太陽

因爲地球的「自轉」,人們能夠看到日出日落,人們日出而做,日落而息,因此就把這一週期現象定義爲「天」。

地球除了自轉,還在圍繞太陽公轉,因此公轉一週就被定義爲一「年」。

從這些現象就能看出來,很早以前的人們,是以「天文現象」來肯定時間的。

再後來,人們爲了把時間定義得更「精確」,就把一天平均劃分爲 24 等份,這就是「時」。

一樣地,把 1 小時劃分 60「分鐘」,1 分鐘劃分爲 60「秒」。

這樣,時間的基本單位「秒」就被定義出來了。

因此,秒與天的關係就是這樣的:

1 秒 = 1 / 24 * 60 * 60 = 1 / 86400 天

這些定義,都與「地球自轉」和「太陽」息息相關。

可是,後來人們發現,地球的公轉軌道並非一個正圓,而是一個「橢圓」,也就是說公轉速度是「不均勻」的,這意味着什麼呢?

因爲「天」是經過在地球上,觀測太陽照射這個同一位置的時間測出來的,公轉軌道是橢圓,意味着天天照射同一位置的時間也有偏差了

也就是說,依據地球公轉計算出的「天」不是等長的,那根據天推算出的秒,天然也不是「等長」的。

很明顯,這裏的計算存在偏差。這怎麼辦?

聰明的人們就想到,把一年內全部天的時長加起來,而後求「平均」,獲得相對固定的「天」,而後再計算得出「相對平均」的秒,這樣就減少了偏差。

肯定了天文規律,人們開始製造「鐘錶」,把時間表示出來。

從擺鐘到機械鐘,再到現代普遍使用的石英鐘,鐘錶的製做工藝愈來愈高,時間精度也愈來愈高,現代石英鐘天天的計時偏差只有「千分之一秒」。

因此,在 1927 年,人們以基於「天文現象」+「鐘錶計時」,確立了第一套時間標準:世界時(Universal Time,簡稱 UT)

咱們常常聽到的「格林尼治標準時間」(Greenwich Mean Time,簡稱 GMT),就是指的世界時,由於世界時是在這個英國倫敦格林尼治天文臺觀測計算出來的!

可是,隨着科技的發展,人類對太陽的觀測愈來愈精準,有意思的事情發生了。

人們發現,地球天天的自轉速度也「不是勻速」的,地球的自轉受到潮汐、地殼運動、冰川融化、地震等天然現象的影響,愈來愈慢!

這會致使什麼問題呢?

這會致使以前規定的,每一年平均下來一天的時間,如今來看,也是不同長的。

例如,第 1 年算出來平均一天的時間是 23.9997 小時,第 2 年多是 23.998 小時,第 3 年多是 23.999 小時...

那按照 1 秒 = 1 / 86400 天的定義,每年的「秒」,也是不同長的。

這就比較尷尬了,人們以地球自轉爲依據,定義出來的時間,仍是不許!

你可能會想,時間有偏差會有什麼問題嗎?人們依賴不許確的天文現象,不也生活了幾個世紀麼?

確實,對於人們的基本生活影響其實並不大。但隨着人類活動的發展,人們對於高精度的時間場景開始變得愈來愈多。

例如,體育賽事中百分之一秒的差距就能決定勝負,炮彈的發射要精確在千分之一秒內發生,雷達技術甚至須要精確到百萬分之一秒...

尤爲是衛星發射、火箭試驗等航天領域,對高精度的時間系統也提出了愈來愈高的要求!

怎麼辦?怎麼完全解決時間不許的問題?

聰明的科學家們開始思考,既然觀測天文現象沒法解決這個問題,那在微觀層面可否找到比較好的解決方案嗎?

這時,他們開始把目光投向了「微觀世界」。

一秒到底有多長?

讓咱們梳理一下咱們的需求。

一直以來,咱們對於「秒」的定義需求,從本質上講,就是想要一個「徹底穩定」的週期,也就是說,指望每一秒都是固定「等長」的。

而以天文觀測、地球自轉爲基礎的時間測量,作不到這一點。

那在微觀世界層面,是否存在一種元素,它的運動週期是「高度穩定」,不受外界環境影響的呢?

科學家們沿着這個思路開始探索...

好,如今讓咱們把視角下放,來到原子世界。

一個原子雖然很小,但它內部倒是一個很複雜的世界。

每一個原子都有一個原子核,核外分層排布着高速運轉的電子,當原子受電磁輻射時,它的軌道電子能夠從一個位置「跳」到另外一個位置,物理學上稱此爲「躍遷」。

人們發現,原子內的電子發生躍遷時,原子會吸取或放出必定能量的「電磁波」,這類電磁波就是一種「週期運動」,咱們也能夠把它當作原子內部的「振盪」。

基於這個原理,科學家們開始不斷地試驗、研究,嘗試尋找一種運動「週期短、高度穩定」的原子。

終於,科學家們發現確實存在這樣一種原子:銫原子,它內部的振盪週期比其它原子都要更短、更穩定,並且,這個過程基本不受環境因素的干擾。

通過層層試驗,科學家們認爲這是目前人類在地球上可測量到的,運動週期最短、週期最穩定的元素!

以後,科學家們就以以前定義的「秒」爲基礎,去測量一秒內這個銫原子內部電子週期運動的「次數」,測量出來的結果爲 9192631770 次(91 億+次)。

基於此,科學家們決定「拋棄」原來基於天文測量的秒,從新定義「秒」的時長,就是這個高度穩定的運動週期。

所以,在 1967 年,國際度量衡大會決定採用,以銫原子躍遷 9192631770 個週期,所持續的時間長度定義爲 1 秒!

注:這個測量原理和測量過程比較複雜,這裏這些物理細節簡化了。不用太過糾結這個數值是怎麼測量出來的,你只須要理解,這個微觀原子內部的振盪週期是很是穩定的,它比以前根據天文現象測量出來的秒,要精確多得多。

而基於這個銫原子振盪製造出來的時鐘,咱們就把它稱之爲「原子鐘」。

有了原子鐘,這就意味着,原子鐘輸出的每一秒,都是絕對「等長」的,很是穩定,這樣一來,就實現了「精準計時」!

這個精確程度能夠達到多高呢?

2000 萬年不差 1 秒!可見其精準程度之高。

科研技術還在發展,精密設備和測量能力也愈來愈高,最新的原子鐘甚至能夠達到 1 億年不差 1 秒!

有了原子鐘,人們基於原子鐘又確立了一套新的時間標準,叫作「國際原子時」(International Atomic Time,簡稱 TAI)

科學家們規定,從 1958-01-01 00:00:00 起,用原子時開始計時,它每走的一秒,都是很是精確的一秒(固定等長),實打實的一秒,徹底穩定的一秒。

這個方案很是棒,至此終於解決了秒不固定長的問題。

那有了這個國際原子時,能否讓它直接取代掉前面說的——以天文現象計時的「世界時」呢?

答案是否認的,這個問題遠比想象的複雜得多,這是爲何呢?

世界標準時間是怎麼來的?

如今,科學家制定出了兩套時間標準:

  1. 世界時:基於天文現象 + 鐘錶計時,永遠與地球自轉時間相匹配
  2. 國際原子時:基於原子鐘計時,每一秒的週期徹底等長且固定

假設咱們以國際原子時爲時間標準,那會發生什麼現象呢?

由於原子時很是穩定,但世界時隨着地球自轉變慢,會愈來愈慢,就會發生這種現象:

  • 原子時走得快,世界時走得慢,時間越久,二者差距愈來愈大
  • 日復一日,幾百年後,世界時的正午 12 點是太陽高照的時刻,而原子時可能已經走到了下午 2 點了
  • 幾千年後,太陽高照的時刻,原子時可能已經走到了晚上 8 點

​晚上 8 點是太陽高照的時刻,你能想象這種狀況嗎?

這太顛覆咱們的生活認知了...

基於天文測算的世界時,已經指導咱們人類生活了上千年,人類早已習慣了這種時間標準,直接被原子時取代,確定是不能接受的。

但咱們又須要原子時這種高度穩定的計時標準,來發展科學研究,二者發生矛盾,這怎麼辦?

科學家們又開始思考,終於想到一個互相兼容的解決方案。

既然兩套時間標準都很重要,那二者都保留,不會互相取代。

咱們能夠再創建一套「新的時間標準」,這套時間以「原子時爲基準」,開始計時,走的每一秒都是穩定、精確的。

同時,爲了兼顧基於天文測量的世界時,人類會「持續觀測」世界時與這個新時鐘的差距。

若是發現二者相差過大時,咱們就「人爲」地調整一下這個時鐘(加一秒或減一秒),讓二者相差不超過 0.9 秒。

例如,這個時鐘自己比世界時走得快,通過一段時間後,若是發現二者相差愈來愈大,那就給這個時鐘「加一秒」,讓這個時鐘在 23:59:59 的下一秒變爲 23:59:60 秒,讓它與世界時差距控制在 0.9 秒之內。

這個操做過程,至關於讓快的時鐘稍微「等」一下走得慢的世界時。

而加的這一秒,科學家把它定義爲「閏秒」。

是否是挺有意思?據說過閏年,沒想到還有閏秒!

固然,當地球自轉速度變快時,這裏也有多是減一秒,即從 23:59:58 直接跳到 00:00:00。 但這種狀況比較少,大部分狀況下,地球自轉速度是愈來愈慢的。 目前,全球已累計加過 27 次閏秒,最近一次閏秒調整,是在北京時間 2017 年 1 月 1 日的 07:59:59 變爲 07:59:60 秒。

這麼作的好處在於,這個時鐘的每一秒的計時依舊是精確的,並且還兼顧了平常生活使用的世界時,一箭雙鵰!

因爲這個時鐘是基於原子時 + 世界時「協調」得出的,因此科學家們把它定義爲協調世界時(Coordinated Universal Time,簡稱 UTC)。

看到了麼?咱們在開發時常常看到的 UTC,原來是這樣來的!

有了這個研究成果,有技術能力的國家都紛紛製造本身的原子鐘,而後計算協調世界時。

同時,爲了進一步下降原子鐘的測量偏差,每一個國家會在每月,統一上報本身計算的協調世界時到一個權威機構,而後這個權威機構會根據各國實驗室的精度,進行加權計算,算出「最終」的協調世界時。

以後,再把這個最終的時間下發到各個國家,讓各個國家進行「對錶」校準,保證全世界的時間偏差在 100 納秒之內。

至此,科學家們創建的這套時間標準,就是咱們如今沿用至今的「標 準 時 間」!

值得一提的是,配合計算協調世界時的國家,也有中國,這個實驗室就是「中國科學院國家授時中心」,它位於中國的陝西省西安市臨潼區,持續維護中國的標準時間。

爲何國家授時中心會設立在陝西省?由於陝西省的地理位置處於中國的中部,從這個位置向各地廣播時間時,對全國每一個地區距離都是相對平均的。

以後,中國會在本身算出的協調世界時的基礎上,再加 8 個小時(中國在東八區),最終得出來的時間,就是「北京時間」!

沒錯,就是咱們常常在新聞播報上聽到的,北京時間。

是否是挺有意思?北京時間並非在北京產生的,而是在陝西省,並與參與世界時間的制定和校準。

至此,全新的世界標準時間確立了,這套時間標準於 1972 年正式肯定,一致沿用至今。

有了標準時間,那麼接下來的問題就是,這個標準時間究竟是如何同步到咱們的電腦、手機、電子設備上的呢?

這就是下面要講的「授時」。

計算機如何同步時間?

到如今咱們知道,世界標準時間和北京時間是怎麼來的,但北京時間的產生是在陝西省,難道校準一次時間須要跑到這裏嗎?

很顯然是不須要的。

位於陝西省的中國科學院國家授時中心,產生北京時間後,會經過一系列方式,把這個時間廣播出去,這個過程,就叫作「授時」。

具體怎麼作呢?

國家授時中心提供不少授時方式,例如無線電波、網絡、電話,均可以把時間廣播出去。

一般來講,無線電波的傳播速度更快、傳播偏差小,因此授時中心會經過這種方式,把時間發送給全國各地的「時間服務器」。

時間服務器有了準確的時間後,再經過其它方式(例如網絡)廣播到下一層的終端用戶使用。

​通過這麼一番研究,到這裏咱們就能夠解釋文章開頭的問題了。

一個時間服務器,原來是經過國家授時中心同步時間,而後再給其它終端提供時間同步服務的。

那咱們的計算機如何和它保持同步呢?

你可能會想,最簡單的方式就是,客戶端向服務端「請求獲取」標準時間,服務端響應時間數據,客戶端修改本身的「本機時間」便可。

但事情沒你想的這麼簡單。

由於數據在網絡傳輸過程當中,也是須要時間的,這個時間也會影響到時間的準確性。

這怎麼辦呢?

因而人們想了一種方案,當計算機在作時間校準時,也須要把網絡延遲計算進去,最後「修正」這個同步過來的時間,下降偏差。

如今,已經有個軟件已經把這一切都作好了,若是你瞭解一些運維相關的工做,就會知道,咱們部署應用程序的服務器上,都會啓動一個「自動校準」時間的服務,這個服務就是 NTP(Network Time Protocol),它能夠保證每臺機器的時間與時間服務器保持同步。

那 NTP 是怎麼同步服務器時間的呢?

這裏就涉及到 2 個重點:

  1. NTP 如何同步時間?
  2. 同步時間時,對正在運行的程序有沒有影響?

先來看第一個問題:NTP 如何同步時間?

簡單來說,它是經過在網絡報文上打「時間戳」的方式,而後配合計算網絡延遲,從而修正本機的時間。

根據圖示能夠計算出網絡「傳輸延遲」,以及客戶端與服務端的「時間差」:

  • 網絡延時 = (t4 - t1) - (t3 - t2)
  • 時間差 = t2 - t1 - 網絡延時 / 2 = ((t2 - t1) + (t3 - t4)) / 2

這個計算過程假設網絡來回路徑是對稱的,而且時延相同。

這樣一來,客戶端就能夠「校準」本身的本機時間了,與服務端保持同步,這個時間偏差在廣域網下是 10ms - 500ms,在局域網下一般能夠小於 1ms。

再來看第二個問題:同步時間時,對正在運行的程序有沒有影響?

例如,咱們不少時候寫的程序代碼是這樣的:

t1 = time.now()
// 時間發生校準
t2 = time.now()

// t2比t1小怎麼辦?
elapsed = t2 - t1
複製代碼

t2 的時間真的會比 t1 小嗎?

這裏就牽涉出 2 個概念:牆上時鐘、單調時鐘,它們之間有什麼區別呢?

  • 牆上時鐘:一般就是指前面講到的協調世界時 UTC,校準時間後,可能發生回撥
  • 單調時鐘:計算機自啓動之後經歷的納秒數,不會回撥

通常咱們寫的代碼,像上面程序調用的「時間 API」,一般獲取的時間是牆上時鐘,因此,若是時間發生校準,就可能會發生「時光倒流」的狀況。

這必然對程序產生很大的影響,怎麼解決這個問題呢?

幸運的是,NTP 在校準時間時,提供了 2 種方式:

  1. ntpdate:一切以服務端時間爲準,「強制修改」本機時間
  2. ntpd:採用「潤物細無聲」的方式修改本機時間,把時間差均攤到每次小的調整上

也就是說,ntpd 當接收到須要「回撥」的時間時,會讓本機時間走得「慢」一點,小步調整,逐漸與服務端的時鐘「對齊」,這樣一來,本機時間依舊是遞增的,避免發生「倒流」。

當咱們在配置 ntp 服務時,須要格外注意這種狀況。另外,在編寫程序時,也要注意調用的時間 API 獲取的是哪一個時間,避免業務邏輯發生異常。

至此,咱們從看似簡單的時間問題,一步步深挖到時間的定義,再到時間是如何同步到計算機和終端設備的,怎麼樣,有沒有解答了你心中的不少疑惑?

總結

好了,總結一下。

這篇文章咱們講了很是多的概念,這裏咱們再從新梳理一遍。

一、人類的早期生活,依靠觀測「天文現象」來測量時間,基於地球自轉規律,定義了一套時間標準:「世界時」。

二、後來人們發現,因爲地球公轉軌道是一個橢圓,而且地球自轉還受到地球內部的影響,自轉速度愈來愈慢,人們發現世界時測算出的時間「不許」。

三、科學家們開始從「微觀世界」尋找更穩定的週期運動,最終肯定以「銫原子」的振動頻率爲基準,製造出了「原子鐘」,確立了「世界原子時」,並從新定義了「秒」長度,時長高度精確。

四、但因爲人類社會活動已高度依賴「世界時」,因此科學家們基於「原子時」和「世界時」相互協調,最終確立出新的時間標準:「協調世界時」,把它定義成了全球的時間標準,至此,世界標準時間誕生。

五、中國基於「協調世界時」再加上 8 小時時區之差,確立了「北京時間」,並廣播給整個中國大地使用。

六、「國家授時中心」把北京時間廣播給全國的「時間服務器」,咱們生活中使用的時間,例如計算機,就是經過時間服務器自動同步校準的。

七、計算機經過 NTP 完成和時間服務器的「自動校準」,咱們的應用程序基於此,才得以獲取到準確的時間。

八、NTP 服務應該採用潤物細無聲的方式同步時間,避免時間發生「倒流」。

後記

這篇文章是我有史以來,最難寫的一篇,由於其中有大量科普類知識,涉及範圍之廣遠超個人想象。

在寫這篇文章時,我至少閱讀了 30 篇以上的資料,不少時候會由於一個很小的細節,又深挖出更多相關的領域的知識,讓我應接不暇。

例如,銫原子的振動頻率是怎麼測量的?爲何能測量得這麼精確?各個國家的原子鐘爲何會有差別?計算機是如何處理閏秒的?時區是怎麼來的?本初子午線是什麼?...

不少細節我其實並無展開來說,我已盡力避開講那些晦澀難懂的物理知識,只保留了重要的理論概念,但願你理解了這其中的原理。若是有些細節你沒有讀懂,能夠先嚐試多讀幾遍,也能夠與我進一步交流。

同時,在查閱資料過程當中,真切地感嘆人類研究成果之偉大,能把時間的偏差,縮小到幾億年的精度,敬佩之情無以言表。

咱們在寫代碼時,看似調用了一個簡單的時間 API,可曾想過,背後倒是人類多少年來的智慧結晶。但願這篇文章能解答你對時間的種種疑惑。

若是你對時間這個話題的學習意猶未盡,還關注個人公衆號「水滴與銀彈」,在後臺回覆「時間」,獲取更多我整理的資料學習。


想看更多硬核技術文章?歡迎關注個人公衆號「水滴與銀彈」。

我是 Kaito,是一個對於技術有思考的資深後端程序員,在個人文章中,我不只會告訴你一個技術點是什麼,還會告訴你爲何這麼作?我還會嘗試把這些思考過程,提煉成通用的方法論,讓你能夠應用在其它領域中,作到觸類旁通。

相關文章
相關標籤/搜索