利用原生 JavaScript 計算各時區時間

之前有介紹過 Moment.js,透過它的 moment-timezone 套件,就可以很輕易地用來計算各個時區的時間。不過今天要透過原生的 JavaScript(Vanilla JS)來試著解決這個問題。

為什麼會有這篇文章呢,其實是在參加六角學院的 JS 地下城挑戰。除了不定時釋出新的題目外,更有特定的 BOSS 弱點要使用特定的技術才能完成。像這一題就要求只能用原生、不能用套件,甚至要寫一篇文章來介紹挑戰過程,所以這裡會先介紹 JS 如何計算各個時區的時間,接著再附上這題的挑戰狀況。

利用 JavaScript 計算各時區時間

其實 JavaScript 的 Date 物件,有個方法叫做 toLocaleString(),只要搭配適當的參數,就能夠轉成各個時區、各個語言的(每個國家表示時間的方法不同,有人用 YYYY-MM-DD,有人用 DD/MM/YYYY)表示方法。基本用法大概是:

new Date().toLocaleString('language', {...options});

舉個例子,如果我們要以臺灣的表示法表示臺北時區的話,就可以用:

new Date().toLocaleString('zh-TW', {timeZone: 'Asia/Taipei'});

輸出大概會是:

2019/2/2 上午2:56:27

舉一反三,如果要以美國的表示法表示紐約時區,就可以:

new Date().toLocaleString('en-US', {timeZone: 'America/New_York'});

輸出就會是:

2/1/2019, 1:57:17 PM

options 裡面還有很多參數可以用,例如如果要 24 小時制的話,可以加上 hour12: false 的選項,詳細可以參考 MDN 的介紹。

UTC?GMT?差在哪裡?

雖然到這裡這題就大致做完了,不過還是順便說一下這兩個東西。還記得小時候地理課本都講我們的時區是 GMT+8,長大以後不知道為什麼大家都講 UTC+8。

關於 UTC 和 GMT 的問題,可以參考泛科學的這篇文章:到底是 GMT+8 還是 UTC+8 ?,是個不錯的科普小知識。不過,在寫 JavaScript 的時候,通常看到 UTC 指的就是國際標準時間。舉個例子:

const now = new Date();
now.getHours(); // 取得本地的小時(0~23)
now.getUTCHours(); // 取得國際標準時間的小時(0~23)

比較特別的大概只有 getTime(),會取得由 1970-01-01 00:00:00 UTC 開始,到現在經過的毫秒數。並沒有 getUTCTime() 這種東西。

1970-01-01 是什麼日子?

這其實是 Timestamp(又稱 UNIX Timestamp、POSIX Timestamp)定義的。在有些地方不能用字串來存時間,只會存數字,所以當年工程師們就定義了 1970 年的元旦當作起始點,並用之後經過的秒數來當作 Timestamp,例如我寫這篇文章的時間(2019-02-02 03:16)的 Timestamp 就可以表示為 1549048560

順帶一提,Timestamp 不會把潤秒算進去 XD

所以第四題怎麼做

這題應該要做到這樣:點此看線上設計稿

大概講一下,基本上解出各國的時區,表示成 24 小時制,就差不多了,剩下就是字串處理了。例如我們已經算出 2019/2/1 03:16:00 的話,只要透過 split() 拿到後半部的時間、再用 slice()substring() 保留時和分的部分,就可以算出右邊的時鐘了。左邊的部分,基本上也是 split() 兩次,把年、月、日分開來重組,就能算出左邊的日期了。

別忘記用一個 setInterval,確保你的時鐘會跟著走。附上這題的 程式碼Demo

延伸閱讀

最後再介紹一個東西。雖然 Moment.js 帶了一個 format() 方法,讓我們不管是 'YYYY-MM-DD'、還是 'DD/MM/YYYY' 都可以很輕鬆的輸出,但你知道其實這表示法有國際標準嗎?看看什麼是 ISO 8601 吧。

如果你也想挑戰的話,歡迎看看六角學院的 說明影片