程式處理時間的原則
花了點時間讀 LUXON.js 的文件,其作者先前是 moment.js 的開發者,覺得受到啟發,筆記一下在程式中處理時間重要觀念,另外搭配一些自己查到的補充資料。
觀念
- 不論人類怎麼依據歷史政治文化居住地點改變時間的表示方式,世界上的每個地方同一時間所經過的秒數都是相同的,儘管時鐘顯示的時間不同。時區(timezone)、時差(time offset) 都只是人類觀點的產物。
- 時差 (offset) 是指所在地和 UTC 的時間差。像台北就是 +8 。代表台北比 UTC 快了 8 小時。
- 時區 (time zone) 通常用 IANA string表示,帶表該地點的時間和 UTC 之間差異的規則,例如
Asia/Taiepi或是America/NewYork,同樣時區與 UTC 的時間差在一年中並不一定總是固定的,可能會因為日光節約時間而改變,例如America/NewYork在 3~11月 會把時間撥快1hr -4,其他月份是-5。- 不同的 IANA 可能會有相同的 time offset,這很直觀,想想那些在同一個經線上的國家。
- 就算一個 IANA 現在沒有日光節約時間(DST, daylight saving time),也不代表該時區以前沒有
- 固定時差 (fixed-offset timezone) ,我們可以指定一個固定的時差,例如 UTC+7,代表這個時間永遠比 UTC 快七小時。
- GMT (Greenwich Mean Time) 格林威治標準時間是 1972 年以前的稱呼,現在大家都用 UTC (Universal Time Coordinated)。
- 常常會聽到MST(山區標準時間), CST(中部標準時間), EST(東岸標準時間),這些是特定地點的時差代稱,不同國家的人會有自己習慣的稱呼,甚至還可能會有相同名稱,這些邏輯留給格式化去顯示就好,不要拿來運算。
- ISO8601 是目前最通用和全世界的人溝通時間的標準,盡量多使用
- 如果沒有時區符號,就代表是當地時間,有offset的話就是指定time-offset時區的時間
- 可以只表示日期 (
2022-11-27) - 可以表示日期時間 (
2022-11-27T21:00:00),但因為沒有時區可能會造成誤會 - 用 Z 表示 UTC +0 時區的時間,Z是Zero的意思 (
2022-11-27T21:00:00Z) - 用 正負 hh:mm 表示時差(
2022-11-27T21:00:00+08:00) - 其他細節請參閱 Wiki ISO8601
開發原則
- 盡量讓 Server 使用 UTC 時間,讓 Server 的程式以 UTC 的角度來存取、處理時間。把時間想成是一個數字 epoch milliseconds 就好。
- Docker Container 預設的時間就是 UTC 。
- 如果可以,在資料庫中盡量以 UTC 存取時間,如果不行的話輸出成 ISO8601 時也要盡量帶 TimeOffset 資訊。
- 跨系統間的溝通使用 ISO8601 ,使用 Z 或是 Offset 都可以,因為不管哪種格式,都能夠被解讀成全域時間線的某個時間點。
- 時區只作為格式化使用,一般來說你完全不需要處理時區。
- 讓 Client 端根據時區在顯示時格式化,因為 Client Side 才有時區資訊。
以 js 的 datetime library Luxon 為例
這些問題都是獨立於語言之外的,理論上是可以擴展到不同語言的。