GMT UTC CST ISO 夏令時 時間戳,都是些什麼鬼?
✍前言
你好,我是A哥(YourBatman)。
日期/時間的處理是平時開發中非常常見的場景,若只是簡單的格式化場景那就還好,一旦涉及到時區、跨地域跨時區時間轉換場景,甚至當還有GMT時間、UTC時間等一堆概念堆上來的時候,總是心理發虛,招架不住。
在地球村的資訊化時代背景下,跨國企業/跨國做生意的公司越來越多,所以我們程式設計師遇到不同時區之間的日期/時間轉換/顯示的概率大大增加。譬如說:電商平台的商品下單時間,你給中國人頁面里展示北京時間是ok的,但你總不能給美國人也展示北京時間吧?否則美國人看到很多訂單的下單時間是凌晨1、2點,還以為午夜凶鈴呢。
Java在版本8之前用Date類型來表示日期/時間,自版本8起引入了JSR 310日期/時間類型。兩套體系對於本地時間、時區時間、帶時區的格式化都有著不同的處理辦法。
A哥因為跨時區日期轉換問題,最近搞了一起生產事故,為此我痛定思痛,決定把經驗整理成文,目的是以後再也不踩這方面的坑,同時也幫助大家。
本部分一共會分兩篇文章敘述:
- 概念篇:科普GMT、UTC、時區、時間戳、夏令時等常見概念以及背景
- 實戰篇:在1的基礎上(概念必須先知曉,否則實戰無法進行),Java是如何來處理GMT/UTC時間、時區、偏移量、夏令時…的
這兩篇文章搞完,自己再也不用不擔心在日期/時間方面埋bug了。相信我,這兩篇文章十分具有收藏價值。
本文提綱
版本約定
- JDK:8
✍正文
下面將圍繞一些日期/時間的概念分別做主題講解,這些名詞你無一例外的都聽過,但我猜測大概率你並不理解,甚至是知曉它們的區別。
GMT:格林威治時間
格林威治(也稱:格林尼治)時間,也叫世界時(Universal Time),也叫世界標準時間。是指位於英國倫敦郊區的【皇家格林尼治天文台】的標準時間,是本初子午線上的地方時,是0時區的區時。
眾所周知,天朝統一用的北京時間是位於東八區(+8)與標準時間相差8小時。什麼含義?舉個例子:若GMT(英國倫敦的格林威治)現在是上午11點,那中國北京時間現在就是 11 + 8 = 19點(下午7點)。
將這個公式再抽象一下,可表示為:本地時間=GMT+時區差
北京位於東八區,則時區差N=+8,美國紐約位於西五區,則時區差N=-5。這麼算來,若北京時間是晚上23點的話,美國紐約時間就是當天上午10點(23 – 8 – 5 = 10)
憑什麼格林威治作為標準時間?
你可能會問,大家都有腰間盤,為何格林威治的那麼突出呢?
大背景是這樣子的:19世紀開始,世界各國來往開始頻繁,而歐洲大陸、美洲大陸和亞洲大陸都有各自的時區,為提高溝通效率避免混亂,各國的代表1884年在美國華盛頓召開了國際大會,選出英國倫敦的格林威治作為全球時間的中心點,並由它負責維護和計算,從1924年開始,格林威治天文台每小時就會向全世界播報時間(截止到1979年)。
在美國華盛頓開會,確定英國倫敦作為時間中心點,還蠻滑稽O(∩_∩)O哈哈~
其實選擇英國格林威治最主要原因是:當時大部分的船隻都已經以格林威治子午線做為參考標準,畢竟曾經的英國可是日不落帝國,大航海時代末便開始稱霸世界,拳頭裡面出政權。
格林威治天文台在計時領域的權威是非常大的,譬如離我們最近的一次「時間風波」:在即將跨世紀的時候,世界各國對21世紀到底應該從2000年開始還是從2001年開始爭論不休,最終還是格林威治天文台出面平息了爭論,開新聞發布會宣布21世紀始於2001年。
地球自轉
地球繞自轉軸自西向東的轉動(太陽東起西落),所以東時區的人會比西時區的人早一些看到太陽,從而時間上會早一點。
以本初子午線為中心,按照地球自轉方向,每隔經度15°劃分一個時區的方法,全球共分為24個時區:東1區至東12區,西1區至西12區,其中東西12區跨度都是7.5°也叫半時區。
中國有哪幾個時區?
1個,這是一個錯得比較合理的答案。合理是因為中國雖然幅員遼闊,但全國使用統一的北京時間,所以很容易被誤以為只有一個時區。
錯是因為拍腦袋想一想就知道,中國東西橫跨5000+公里,怎麼可能只躺在一個時區呢?正確答案是:中國大陸共橫跨5個時區,各個時區大致的方點陣圖如下:
看圖就清晰明了的知道天朝為何選用東八區時間作為全國標準時間了吧?沒錯,僅就因為北京在東八區,即使地圖上只有彈丸大小,但就是這麼豪橫。
中國用統一時間在溝通上確實方便得多,減少了很多不必要的麻煩。但是也帶來一些「小問題」,比如新疆的朋友(位於東5/6區)實際比東八區的北京時間晚了 2-3個小時,我們正常7點天黑準備吃完飯的時候,新疆那邊還太陽當空照呢,還蠻有意思的~
美國有哪幾個時區?
說到時區,就不得不提及計劃再次偉大的美國了。美國同樣的幅員遼闊,橫跨了4個時區:
如圖所示共有四個時區時間,按照圖中顏色劃分開(並非嚴格劃分,不然出現同一小區隔壁時間比你晚1小時就尷尬了),從右到左依次為:
- 東部時區(ET):西5區,代表城市:華盛頓特區、紐約、邁阿密等,也稱紐約時間。北京時間 = ET + 13h
- 中部時區(CT):西6區,代表城市:芝加哥、休斯頓等。北京時間 = CT + 14h
- 山地時區(MT):西7區,代表城市:丹佛、鳳凰城等。北京時間 = MT + 15h
- 太平洋時區(PST):西8區,代表城市:洛杉磯、拉斯維加斯、西雅圖等。北京時間 = PST + 16h
GMT和Http協議的淵源
這是我「偶遇」的一個知識點,在這裡也一併分享給你。
Http 1.1協議對日期時間傳輸格式是有嚴格規定的,支援如下三種格式:
其中第一種格式是互聯網傳輸的標準格式,也是現行的標準。2、3種純是為了兼容Http 1.0而設計,現在基本已經淘汰沒人再會使用,所以事實上的格式只有第一種這1種,作為一個有經驗的程式設計師對這種格式應該不陌生。
另外,還有個關鍵的知識點:所有HTTP日期/時間戳都必須用格林威治標準時間(GMT)表示,沒有例外。對於HTTP來說,GMT完全等於UTC(協調世界時)。
當然嘍,這一切都是由瀏覽器自動幫你完成的,畢竟Http協議是瀏覽器去搞的不是
UTC:世界標準時間
Coordinated Universal Time直譯為:世界協調時間。它是以原子時作為計量單位的時間,計算結果極其嚴謹和精密。它比GMT時間更來得精準,誤差值必須保持在0.9秒以內,倘若大於0.9秒就會通過閏秒來「解決」。
原子時:物質的原子內部發射的電磁振蕩頻率為基準的時間計量系統。美國的物理實驗市在2014年造出了人類歷史上最精確的原子鐘,50億年誤差1s,可謂相當靠譜了。中國的銫原子鐘也能確保2000萬年誤差不超過1s。
大事記:1979年12月初內瓦舉行的世界無線電行政大會通過決議,確定用「世界協調時間(UTC時間)」取代「格林威治時間(GMT時間)」,作為無線電通訊領域內的國際標準時間。
UTC和GMT的區別
UTC和GMT都稱作世界標準時間,為毛有了GMT還搞出個UTC,到底有何區別,下面做出簡述。
GMT:老的時間計量標準,根據地球的自轉和公轉來計算時間的,自轉一圈是一天,公轉一圈是一年。但是呢,地球公轉的軌道是橢圓形的:
並且後來人們發現地球的自轉時間也並不是恆定的,這麼一來就會造成有一天時間長一些,有一天時間短一些的情況,誤差較大給人感覺時間不那麼「精準」了,因此迫切需要一個更加精準的方案來計時,UTC誕生了。
UTC:1967年人類製作出原子鐘,從而「發明」了UTC時間正式投入使用。它是真正意義上的標準時間,以原子鐘所定義的秒長為基礎,UTC時間認為一個太陽日(一天)總是恆定的86400秒(24小時)。
UTC是協調時間,含義為:一切以我為基準,全部想我看齊。所以稱它為世界標準時間是沒毛病的,而把GMT稱作格林威治當地時間更為合適(也叫舊的標準時間)。
UTC和GMT的聯繫
由於在大多數情況下,UTC時間能與GMT時間互換。對此很多同學就丈二和尚摸不著頭腦了,他倆這不就一樣的嗎?
其實非也。這裡用通俗易懂的一句話來告知它倆的聯繫:UTC是標準時間參照,像GMT(格林威治時間)、ET(美國東部時間)、PST(太平洋時間)、CST(北京時間)等等都是具體的時區時間。GMT能和UTC直接轉換,僅僅是因為碰巧GMT是0時區時間,數值上剛好和UTC是相等的(不需要精確到秒的情況下,二者可以視為相等),看起來一樣,但是概念含義上請務必區分開來哈。
UTC與偏移量
在日常生活中,我們所使用的時間肯定是本地時間。在只有GMT的時候,本地時間是通過時區計算出來的,而現在UTC才是標準參考,因此採用UTC和偏移量(Offset)的方式來表示本地時間:
這個偏移量可表示為:UTC -
或UTC +
,後面接小時數,分鐘數
。如:UTC +9:30表示澳大利亞中央標準時間,UTC +8表示中國標準時間。偏移量常見的表示形式有:±[hh]:[mm]
、±[hh][mm]
、±[hh]
這三種方式均可。
舉個例子:現在UTC時間是10:30z
(z表示偏移量=0),那麼北京時間現在若是1630 +0800
(下午4點半),對應的紐約時間就是0530 -0500
(早上5點半)。
注意:在UTC的世界裡並無時區的概念,而是偏移量(時間點跟上偏移量才是一個正規的UTC時間),它和時區並無直接關係
可以看到偏移量可以精確到分鐘級別控制,非常精細化。全球只有24個時區(只能精確到小時),但偏移量有「無數個」。當然嘍為了方便溝通,時間日期聯盟組織把世界主要國家/城市的偏移量匯總起來且都給取了個Time zone name
名稱用於溝通,共好幾百個,部分截圖如下:
偏移量和國家/城市名稱的全部對應關係,請參考網址(直接訪問,無需梯子)://www.timeanddate.com/time/zones
CST
CST這個縮寫比較尷尬的是它可以同時代表四個不同的時間:
- CST (China Standard Time) :中國標準時間 UTC+8:00
- Central Standard Time (USA) UTC-6:00
- Central Standard Time (Australia) UTC+9:30
- Cuba Standard Time UTC-4:00
CST到底啥意思就看如何翻譯嘍,所以需要根據上下文語境自行抉擇哈。
ISO
在時間日期上它全稱是ISO 8601,是一種日期/時間表示方法的規範。規定了一種明確的、國際上都能理解的日曆和時鐘格式。
這一ISO標準有助於消除各種日-日慣例、文化和時區對全球業務產生的影響。它提供了一種顯示日期和時間的方式,這種方式是明確定義的,對人和機器都是可以理解的。當日期用數字表示時,它們可以以不同的方式進行解釋。例如,01/05/12可以表示2012年1月5日或2012年5月1日。在個人層面上,這種不確定性可能非常令人沮喪,在商業環境中,它可能非常昂貴。在日期不明確的情況下,組織會議和交付、書寫合約和購買機票都是非常困難的。
ISO 8601通過制定一種國際公認的日期表示方式來解決這種不確定性:YYYY-MM-DD
。例如 September 27, 2012就會被表示為2012-09-27。
很多開發語言內置了一些常用的ISO標準日期/時間格式,如Java中的:
- ISO.DATE:yyyy-MM-dd, e.g. “2000-10-31”
- ISO.TIME:HH:mm:ss.SSSXXX, e.g. “01:30:00.000-05:00”
- ISO.DATE_TIME:yyyy-MM-dd’T’HH:mm:ss.SSSXXX, e.g. “2000-10-31T01:30:00.000-05:00”.
夏令時
DST(Daylight Saving Time),夏令時又稱夏季時間(可沒有冬令時哦)。它是為節約能源而人為規定地方時間的制度(鼓勵人們早睡早起,不要浪費電,夏天日照時間長盡量多用自然資源),全球約40%的國家在夏季使用夏令時,其他國家則全年只使用標準時間。正在使用夏令時的代表國家:美國、歐盟、俄羅斯等等。
每年的夏令時時間段還不一樣(一般在3月的第2個周日開始),比如美國2020年夏令時時間是:2020年3月8日 – 2020年11月1日。具體做法是:在3.8號這天將時鐘往前撥撥1個小時,11.1號這天還原回來。
中國在1986 – 1992年短暫搞過一段時間,但太麻煩就「廢棄」了
大事記:目前全世界有近110個國家每年要實行夏令時。 自2011年3月27日開始俄羅斯永久使用夏令時,把時間撥快一小時,不再調回。
時間戳
現實生活的世界裡,時間是不斷向前的,如果向前追溯時間的起點,可能是宇宙出生時,又或是是宇宙出現之前,但肯定是我們目前無法找到的,我們不知道現在距離時間原點的精確距離。所以我們要表示時間, 就需要人為定義一個原點。它就是:格林威治時間(GMT)1970年1月1日的午夜0點0分0秒。
時間戳一般指的UNIX時間,或類UNIX系統(比如Linux、MacOS等)使用的時間表示方式。定義為:從UTC時間的1970-1-1 0:0:0
起到現在的總秒數(秒是毫秒、微妙、納秒的總稱)。
但是不可忽略的一個case:由於閏秒的存在,那麼當閏秒發生時,就極有可能出現同一個時間戳表示兩個時刻的情況(類似時鐘回撥),而且閏秒還沒規律所以無法程式式的避免,怎麼破?
這個時候就需要一種專門的對時協議來保證了,它就是:網路時間協議。
網路時間協議
網路時間協議 Network Time Protocol(NTP)是用來使電腦時間同步化的一種協議,它可以使電腦對其伺服器或時鐘源(如石英鐘,GPS等等)做同步化,它可以提供高精準度的時間校正(LAN上與標準間差小於1毫秒,WAN上幾十毫秒),且可介由加密確認的方式來防止惡毒的協議攻擊。
NTP的目的是在無序的Internet環境中提供精確和健壯的時間服務,各大作業系統(windows/Linux)對NTP都有實現。
✍總結
簡單地講呢,GMT格林威治時間可認為是以前的標準時間,而UTC時間是現在在使用的世界時間標準;時區是以本初子午線為中心來劃分的,東為正西為負,本處子午線就位於英國倫敦的格林威治;夏令時是地方的時間制度(並非全球標準),施行夏令時的地方,每年有2天很特殊,即一天只有23個小時,另一天則有25個小時。
從源頭上徹底了解了這些概念,將會讓我們在處理與時間相關的問題時如虎添翼。本文介紹了好些個日期/時間方面的概念,文字偏多,所以建議你收藏起來當作參考書來使用。
下篇文章將會接著本文內容,站在實戰的角度,介紹Java是如何實現GMT和UTC時間的,以及各種case下的使用和避坑指南,歡迎關注我。
♨本文思考題♨
看完了不一定懂,看懂了不一定會。來,文末3個思考題幫你復盤:
- 中國是南半球還是北半球?東半球還是西半球?
- GMT時間和UTC時間有何區別和聯繫?
- 中國有夏令時沒?
☀推薦閱讀☀
- ……
- 7. JDK拍了拍你:字元串拼接一定記得用MessageFormat#format
- 8. 格式化器大一統 — Spring的Formatter抽象
- 9. 細節見真章,Formatter註冊中心的設計很討巧
- ……
♚聲明♚
本文所屬專欄:Java進階,公號後台回復專欄名即可獲取全部內容。
分享、成長,拒絕淺藏輒止。關注【BAT的烏托邦】,回復關鍵字專欄有Spring技術棧、中間件等小而美的原創專欄供以免費學習。本文已被 //www.yourbatman.cn 收錄。
本文是 A哥(YourBatman)原創文章,未經作者允許/開白不得轉載,謝謝合作。