Globalization Design: 理解時區

2021-02-20 萬力王
在處理時區相關問題的時候,我們經常會遇到這樣的縮寫:UTC,GMT,DST,CST,BST等等。我猜測,我們多數開發或者PM會自認為這些都很簡單,但實際上還是在不斷出現不那麼global的問題,而且這些小問題往往還都在我們的認知盲區中。所以接下來,我們不妨花幾分鐘時間來討論下時區相關的概念。

一、時間標準(Time Standard) vs 時區(Time Zone)

A time standard is a specification for measuring time: either the rate at which time passes; or points in time; or both.

https://en.wikipedia.org/wiki/Time_standard

從維基百科上摘取的一段定義,大意是時間標準是度量時間的一種規範,既可指時間流逝的速率亦或指時間點。我們常用的UTC(Coordinated Universal Time)就是現在國際通用的時間標準。UTC的定義由兩部分決定:原子時(TAI - International Atomic Time)和世界時(UT1 - Universal TIme)。原子時可以非常穩定和精確地定義1秒時間(銫-133原子震動9,192,631,770次),由於它很穩定,我們用它來衡量時間流逝的速率,也就是時鐘上秒針轉動的速率;世界時是基於地球自轉的一種時間計量方式,通過它我們可以衡量地球一天有多長。但由於地球自轉因潮汐力等客觀因素,導致自轉速度在不斷變慢,所以人為引入閏秒(leap second)來彌補世界時和地球真實自轉速度之間的誤差。

追溯下歷史,UT最早在1884年被創立,當時選用的Greenwich Mean Time(GMT)作為世界時間標準,把經過經度為0的倫敦格林威治這個地方作為我們現在熟知的本初子午線的原始起點。

之後,UTC最早在1960被引入,最終在多次完善後,從1972年開始替代GMT,自此GMT不再是一個時間標準,而僅僅只是代表一個時區(零時區)。

我們接著說時區:

A time zone is a region of the globe that observes a uniform standard time for legal, commercial and social purposes.

https://en.wikipedia.org/wiki/Time_zone

簡而言之,為了滿足法律、商業和社交需求,我們用時區將全球劃分成不同地區並遵循統一的時間表達方法。剛才說到的GMT是零時區的一個縮寫(也叫Z - Zulu Time Zone),還有CST(China Standard Time)也是一個時區的縮寫,全球各個國家、地區或城市根據時區的劃分使用特定的縮寫。舉個例子,比如我們知道在倫敦的這個時間點 2020-04-27 07:00:00,我們想知道中國是幾點,由於中國在CST時區,倫敦在Z時區,CST時區和Z時區相差8個小時,此時在CST時區,當地時間表示為2020-04-27 15:00:00 CST,UTC時間表示為2020-04-27 15:00:00 UTC+08:00,或者,2020-04-27 02:00:00 UTC-05:00代表了EST(Eastern Standard Time)時區的當地時間。

我們可以發現,UTC時間裡帶上了和零時區的正負時間偏移量。值得注意的是,這個偏移量的最小單位並不是小時,而是分鐘,比如IST(India Standard Time),它的偏移量是UTC+05:30,也就是5個半小時,再如NPT(Nepal Time),它的偏移量是UTC+05:45,5個小時45分鐘。通過這個連結:https://www.timeanddate.com/time/zones/,可以找到所有時區的縮寫和對應的偏移量(註:不同地區可能共用一個時區縮寫,比如BST,在亞洲代表Bangladesh Standard Time, UTC+06:00;在大洋洲代表Bougainville Standard Time, UTC+11:00;在歐洲代表British Summer Time, UTC+01:00)。

綜上,我們現在可以理解清楚UTC和GMT之間的區別了。但由於歷史原因,GMT有一段時間的作用和UTC一樣,只是現在UTC替代了GMT,但很多站點上可能還會保留使用2020-04-27 15:00:00 GMT+08:00的形式來表達國際標準時間,雖然不是什麼大是大非的問題,但結合GMT現存的特定意義,僅有部分歐洲和非洲地區在使用,所以還是更推薦使用當地時區縮寫的形式來表達用戶當地時間。

二、DST (Daylight Saving Time)
為了更好地利用白天的時間,部分國家和地區在春天開始的時候把時鐘往前撥一個小時,此時時間被稱為夏令時,然後在秋天到來的時候再調回去,此時稱為標準時,或者冬令時。多數在北半球的國家會使用DST,一般在每年的3~4月開始,到9~11月結束,每年的具體開始和結束時間並不固定。從這個連結:https://www.timeanddate.com/time/dst/2020.html,可以查到2020年各個國家使用DST的周期,以及歷史上某年的周期。和時區縮寫類似,當某個地區進入夏令時的時候,有一個專門的時區縮寫,比如莫斯科在夏令時用MSD(Moscow Daylight Time), UTC+04:00,按標準時間用MSK(Moscow Standard Time), UTC+03:00(不過莫斯科從2011年開始就沒有使用夏令時了)。

絕大多數高級開發語言都對時區展示有專門的封裝,下面以Java為例,看下如何來處理時區問題。

TimeZone utc = SimpleTimeZone.getTimeZone("UTC");String pattern = "yyyy-MM-dd HH:mm:ss z (zzzz)";DateFormat dfUTC = new SimpleDateFormat(pattern, Locale.ENGLISH);dfUTC.setTimeZone(utc);
String zoneId = "Europe/Vienna";TimeZone tz = SimpleTimeZone.getTimeZone(zoneId);
pattern = "yyyy-MM-dd HH:mm:ss z (zzzz) 'UTC'XXX";DateFormat dfLocal = new SimpleDateFormat(pattern, Locale.ENGLISH);dfLocal.setTimeZone(tz);
Calendar cd = Calendar.getInstance(tz);cd.set(2010, 8, 1, 10, 0, 0);Date dt = new Date(cd.getTimeInMillis());System.out.print("local time:\t");System.out.println(dfLocal.format(dt));System.out.print("UTC time:\t");System.out.println(dfUTC.format(dt));
String abbr = tz.getDisplayName(tz.inDaylightTime(dt), 0, Locale.ENGLISH);System.out.print("abbr.(DST):\t");System.out.println(abbr);

cd.set(2010, 10, 26, 10, 0, 0);dt = new Date(cd.getTimeInMillis());System.out.print("local time:\t");System.out.println(dfLocal.format(dt));System.out.print("UTC time:\t");System.out.println(dfUTC.format(dt));
abbr = tz.getDisplayName(tz.inDaylightTime(dt), 0, Locale.ENGLISH);System.out.print("abbr:\t");System.out.println(abbr);

執行上面的代碼,可以得到下面的輸出:

從JDK1.8開始新增了ZonedDateTime類,可以更簡單明了地從一個已知時區的時間轉換成某個目標時區的時間。
// 注意下,這裡的month是從1開始的,而Calendar裡是從0開始的。ZonedDateTime zdt =       ZonedDateTime.of(2010, 9, 1, 10, 0, 0, 0, ZoneId.of("Europe/Vienna"))                   .withZoneSameInstant(ZoneId.of("Asia/Shanghai"));System.out.println(zdt.format(DateTimeFormatter.ofPattern(pattern, Locale.ENGLISH));

2010-09-01 16:00:00 CST (China Standard Time) UTC+08:00

另外,上面ZoneId構造的時候,類似"Asia/Shanghai"可以替換成"+08:00",但這樣輸出的結果裡是沒有CST和China Standard Time,且都被+08:00替換。

2010-09-01 16:00:00 +08:00 (+08:00) UTC+08:00

從上一部分的描述中,我們可以發現,各個地區的UTC的偏離量,還有DST的規則等等是沒有規律的,是需要日常維護的,但上面獲取到的Vienna的DST時間區間是從哪裡來的呢?

翻看JDK源碼,我們可以發現,SimpleTimeZone.getTimeZone()方法的實現最終可以追溯到ZoneInfoFile這個類。

static {    String oldmapping = AccessController.doPrivileged(        new GetPropertyAction("sun.timezone.ids.oldmapping", "false")).toLowerCase(Locale.ROOT);    USE_OLDMAPPING = (oldmapping.equals("yes") || oldmapping.equals("true"));    AccessController.doPrivileged(new PrivilegedAction<Object>() {        public Object run() {            try {                String libDir = System.getProperty("java.home") + File.separator + "lib";                try (DataInputStream dis = new DataInputStream(                         new BufferedInputStream(new FileInputStream(                             new File(libDir, "tzdb.dat"))))) {                    load(dis);                }            } catch (Exception x) {                throw new Error(x);            }            return null;        }    });}

可以看到,ZoneInfoFile在靜態構造塊中,會去JRE的根目錄加載一個叫tzdb.dat的文件。追根溯源,這個Tzdb來自於IANA提供的TimeZone資料庫,https://iana.org/time-zones,目前維護著最新最全的全球時區相關基礎數據。我們可以通過getVersion方法來查看下系統加載的這個資料庫的版本。

String version = ZoneInfoFile.getVersion();System.out.println(String.format("TZDB[%s]", version));

下面這個截圖是從我本機輸出的結果,可以看出是2015年的版本。

為了能夠應用最新的數據,我們可以替換tzdb.bat這個文件。但從IANA上下載的並不是這種格式的,我們需要用到這個工具:https://github.com/akashche/tzdbgen,它可以幫助我們生成最新的tzdb.bat文件。(根據使用開發語言的不同,下載下來的數據需要再編譯成對應語言的文件,可以在IANA上找到相對應的編譯工具。)除此之外,我們也可以自己實現一個ZoneRulesProvider來定製自己的時區使用規則。

一個確切時間的完整表述都應該有對應的時區,如果沒有明確設置,那麼要麼默認是設備當地時區,要麼是Z時區。

在本地化展示用戶端當地時間的時候,儘量讓用戶端來處理本地化輸出格式,因為客戶端對時間處理的方法一般默認用的是系統設置的當地時區。

如果需要準確輸出某個時間所在的時區名字,在後端的數據存儲和交換過程中,也需要保存時區ID(比如Asia/Shanghai)。

僅通過offset推算的新時間,是無法準確獲取新時間所在的時區名的。比如通過UTC-5,既可以對應EST(Eastern Standard Time),也可以對應ECT(Ecuador Time)。所以如果需要準確輸出時區縮略名或者完整的名字,還需要時區ID。

相關焦點

  • 每日一圖【時區環】
    如果把圖做成環形,對於時區分布和日界線問題就可以更好的理解。  在學習時間計算這部分知識的時候,繪製一幅時區環有助於知識的理解。時區與區時(1)時區的劃分 在國際交往中,使用地方時很不方便。
  • 初中地理知識點歸納:時區
    時區是中學地理學習中較難的內容,同學們在理解上,在進行換算上,都存在一定的困難。我通過這幾年的教學,進行了簡單的小結,通過口訣、公式等方法,幫助同學們進行理解、記憶和換算。   1.用口訣幫助同學們記憶。   即,時刻東進(+)西退(-),日期東退(-)西進(+)。
  • 跨境網絡小知識-時區
    跨境夥伴們,大家好,又和大家見面了,今天為大家帶來與跨境息息相關的小知識-時區。世界時區圖:先簡單理解下,不同的時區的表現的形式就是時間不一致。地球是圓的,每個國家和地區處在不同的經度上,全球不可能同時享受到白天或者黑夜,因為地球自轉一圈是一天,所以不同時區的時間就有了差別。全球共分為24個時區,每15° (360/24)劃分為一個時區。每個時區都有一個中央子午線,全球統一的子午線本初子午線位於英國(日不落帝國的實力可見一斑)。
  • 備忘:初中地理《時區》知識點歸納
    關鍵詞:換算、口訣、公式、理解、記憶。1.用口訣幫助同學們記憶。即,時刻東進(+)西退(-),日期東退(-)西進(+)。也就是說,時刻向東每過一個時區要加上一個小時,向西每過一個時區減去一個小時。2.在計算某時區的中央經線時,用公式:時區數×15°=該時區的中央經線的度數。東西經與時區的東西相同。如,東八區的中央經線為:8×15°=120°故120°E就是東八區的中央經線。西八區的中央經線為:8×15°=120°故120°W就是西八區的中央經線。
  • 中國橫跨5個時區,為什麼不區分時區?
    想必各位讀者都有這個疑問,全世界橫跨時區最大的幾個國家中,比如俄羅斯,美國,加拿大以及中國,前三者都實行了時區制,唯有中國沒有區分時區,全國一個時區,即東八區!我們來看看這些實行了時區的國家是怎麼區隔時區的?中國又為什麼不區分時區?
  • 【今日常識】時區
    一、時區的概念:時區是地球上的區域使用同一個時間定義。1884年在華盛頓召開國際經度會議時,為了克服時間上的混亂,規定將全球劃分為24個時區。二、時區的劃分:地球是自西向東自轉,東邊比西邊先看到太陽,東邊的時間也比西邊的早。
  • 世界時區圖
    為了克服時間上的混亂,1884年在華盛頓召開的一次國際經度會議(又稱國際子午線會議[1] )上,規定將全球劃分為24個時區(東、西各12個時區)。規定英國(格林尼治天文臺舊址)為中時區(零時區)、東1-12區,西1-12區。每個時區橫跨經度15度,時間正好是1小時。最後的東、西第12區各跨經度7.5度,以東、西經180度為界。
  • 地理小常識:時區的計算
    地球上共有360度經度,按照15度一個時區,將全球分為24個時區。以0度經線開始計算,往東方向,依次分為東一區、東二區、東三區.......東十二區;往西方向,依次為西一區、西二區、西三區.....西十二區。其中西十二區和東十二區共佔一個時區,以180度經線為界。如下圖。
  • 張北海:時區和時差
    道理誰都知道,這是因為世界各地不同時區( time zones)而出現的時差( time differences)。那時差的科學定義是什麼?至少按照中國現代漢語詞典,是「(天)平太陽時和真太陽時的差」。聽起來有點玄,又好像與人無關。但凡搭乘噴氣飛機十幾個小時穿越好幾個時區的旅客,尤其從西飛向東,卻因之而身心受苦,於是英文出現了一個新的名詞jet lag。但此一名詞卻沒有恰當中譯。
  • 世界上的時區是怎樣劃分的?
    在地理上我們都知道有個世界時區的表,這個表讓我們一眼就看出在不同的國家的時間,一般的來分析時間時區上有一定的規則的。先看下全球的時區分布情況。俄羅斯時區劃分再說說美國,美國的領土也是經度跨度較多,美國本土,包含夏威夷和阿拉斯加,總共有六個時區。如下圖所示,從左至右它們分別是:美國東部時區 EST,美國中部時區 CST,美國山區時區 MST,美國太平洋時區 PST,以及阿拉斯加和夏威夷也分別擁有各自的時間標準。
  • 時區劃分及區時計算
    東邊時刻與西邊時刻的差值不僅 要以時計,而且還要以分和秒來計算,這給人們帶來很大不便,為了克服時間上的混亂,1884年在華盛頓召開的一次國際經度會議(又稱國際子午線會議),在會議上確定了時區劃分和區時標準。1、時區劃分(1)全球共劃分為24個時區,每個時區佔15個經度。
  • 臺一網民欲提議將「臺灣時區」改為日本時區 被民眾痛罵
    日前有臺灣媒體曝出,一位網民連時區也要「去中國化」,該網民聲稱要「將『臺灣時區』由目前GMT+8提前至GMT+9,與日本相同,脫離中國大陸標準時區」,隨即被島內網友痛罵。臺灣「聯合新聞網」19日報導稱,一位臺灣網民在臺「國發會」「公共政策網路參與平臺」上作出上述提議,他宣稱,「臺灣在過去曾屬於GMT+9時區,與臺灣類似經度的朝鮮、韓國也屬於GMT+9時區,認為臺灣若由GMT+8改為GMT+9,可象徵性地脫離中國(GMT+8)的從屬,讓到臺灣的陸客或是外國旅客意識到臺灣與中國大陸的互不相從屬關係。」
  • 搞清日期、時間與時區
    夏令時與冬令時 Daylight Saving Time(簡稱 DST)又稱「日光節約時制」和「夏令時間」,是一種為節約能源而人為規定地方時間的制度,在這一制度實行期間所採用的統一時間稱為「夏令時間」。一般在天亮早的夏季人為將時間提前一小時,可以使人早起早睡,減少照明量,以充分利用光照資源,從而節約照明用電。。
  • 中國為什麼只用一個時區?
    於是,對於中美俄這種國土面積龐大、橫跨多個時區的國家,如何制定合適的時區,就是一件麻煩的事情。橫跨九個小時的高考一般來說,一個國家制定時區,都會根據約定,儘可能地制定分區時間,使其適合自己。然而過多時區帶來的混亂和麻煩依然不可避免,為此不得不採取多時區制。
  • 一口氣看懂「時區」裡的秘密
    ,將世界劃分為24個時區,東12區和西12區。一個國家十次「高考」那麼剛剛說了,每跨15°經度,便是一個時區,比如英國全國都使用零時區,德國全國都使用東一區。但是對於一些幅員遼闊的國家,比如俄羅斯,美國,中國,事情就變得複雜起來。例如俄羅斯,世界上國土面積最大的國家,整整跨越了十一個時區,做個飛機從東邊往西邊飛,落地時間比起飛時間還早。這種情況下,很難採取統一時區,而更多地則是選擇「多時區制」。
  • ——我們身邊的這個國家竟然擁有世界上最多的時區
    造成如此情況的原因是在1884年在華盛頓召開國際經度會議時,為了克服時間上的混亂,規定將全球劃分為24個時區。根據劃分標準,在中國採用首都北京所在地東八區的時間為全國統一使用時間。美國包括阿拉斯加和夏威夷也劃分為了六個時區。
  • 百達翡麗5110世界時區表
    百達翡麗5110世界時區表  這款編號為5110世界時區表是以城市盤東經120度製作鏤刻,將簡單易用的特質融入世界時間觀念之中,使用者只需按下10點鐘方向的單一按鈕便可輕易地調整兩地時間,即使在轉換時區時也不會影響分針的精確度,不僅能顯示當地時間,更能在同一時間將其它24個時區時間顯示在單一城市環上,
  • 玩轉地理 | 世界時區的那些事
    正式的時區劃分,其中包括24個時區,每一時區由一個英文字母表示。每隔經度15°劃分一個時區,有一個例外,每個時區有一條中央子午線。但由於各種各樣的原因,我們會見到一些奇怪的時區分法  1.半區計時法:根據本國所跨經度範圍,採用與中央經線相差7.5°的時區的邊界經線的地方時。例如,印度採用東5.5區。
  • 臺灣5000人聯署要求把中國時區改為日本時區,結果被臺灣網友罵翻了
    16日,名為「Yohan Ting」的網民在島內「國發會」的公共政策網絡參與平臺上提出一個奇葩的點子:提議臺灣時區由目前的 GMT +8 提前至 GMT +9,與日韓相同,「脫離中國大陸標準時區」。關於時區島內的公共政策網絡參與平臺上,兩派網民留言中,不支持者更多。支持者之所以支持改時區,多數還是覺得可以「更充分利用陽光」,而非藉此「去中國化」。反對一方中,置頂前三位的帖子分別是:「真的有病!連時間都要和倭寇同步。重點是你跟鬼子本來就是不同時區!」
  • 我們為什麼不在同一個時區
    無論如何,時區決定了無論我們在地球上的哪個地方,所使用的時鐘都必須與太陽時保持一致,當你穿越多個時區或與遠在他鄉的人交流時,時間的不同真的會讓人感到痛苦。奇怪的是,時區的發明是為了減少混亂,而不是引起混亂,因為太陽時會隨著你在地球上從一個地方到另一個地方的移動而變化,即使是很短的距離,在人類的大部分歷史中,一天的時間在不同地方都存在差異,即使在14世紀歐洲人開始使用機械鐘之後,這種不一致性依然存在。