[Go 08] 認識時間格式與golang的時區轉換寫法

開發過程中,曾遇過部署到別的平台,時間就變成+0 時區了(例如明明下午五點,部署平台顯示早上九點),這時才發現原來你的時間不是他的時間,而資料庫中也常常用時間戳數字來做紀錄,但顯示給使用者時又要轉成格式化顯示,本篇紀錄各種時間格式的理解與 go 程式對於時間的使用

理解時間的各種顯示格式

時間可以以很多格式化的方式做顯示。例如最常看到的 2021-04-22 17:27:44

標準時間格式

國際標準格式,像是 ISO_8601

  • 合併表示時,要在時間前面加一大寫字母 T
  • 如果時間在零時區,並恰好與協調世界時相同,那麼(不加空格)在時間最後加一個大寫字母 Z
    例如以下這樣的顯示方式:
1
2
2021-04-28T01:51:35Z
2004-05-03T17:30:08+08:00 //+08:00代表比世界協調時間快8小時的時區

UNIX 時間與時間戳

UNIX 時間代表從 UTC1970 年 1 月 1 日 0 時 0 分 0 秒起至現在的總秒數

  • 而 UTC 為世界協調時間(英語:Coordinated Universal Time,法語:Temps Universel Coordonné,簡稱 UTC)是最主要的世界時間標準。
  • 這種你會看到可能是十位數的數字(s:1621999487)或是十三位數的數字(ms:1621999487377),可以透過線上時間戳轉換器得出代表的時間。

時區的轉換

世界各國位於地球不同位置上,,不同地區的人會有不同的地方時間,可以看時區轉換器


golang 時間轉換

接著說明使用 golang 實現以上幾種常見的轉換,而 2006-01-02 15:04:05-0700 是一串 go 獨特神奇的對應順序。可以看time/format.go

大致列出四種轉換:

  1. 將時間戳轉換為時間

  2. 將時間做格式化輸出,golang 語法的時間輸出跟 java 比較不一樣。2006-01-02 15:04:05-0700 對應到 yyyy-MM-dd HH:mm:ss Z,請見golang 與 java time 的對照表記憶順序有點像是06代表年,後面則是1,2,3,4,5,7

  3. 時區轉換: FixedZone(name,位移的秒數),可以自訂時區命名信息,loc := time.FixedZone(“UTC-8”, -8 _ 60 _ 60)第二個參數轉移多少秒,可以改+8 時區等等

  4. 時區轉換: LoadLocation(name),可以輸入空值,”UTC”,”Local”,或是時區的資料庫 EX: “Asia/Taipei”,命名使用的資料庫為IANA Time Zone database,好處是不用自己輸入到底是+ 8 還加多久,知道時區命名就好,但是背後的定義還是會依下列順序去找尋對應資料:

    • ZONEINFO 環境變數所指定的 zip 文件
    • Unix 系统中已经安装的
    • $GOROOT/lib/time/zoneinfo.zip,

因此如果在 windows 系统上,没有安装 go 語言環境,time.LoadLocation 會失敗,建議用 time.FixedZone。

另外在 docker 環境裡也要注意使用的 image 是否已經有包含這些資料,否則會出現 unknown time zone XXXX 的錯誤,解決方法需要加入以下設定

1
2
3
4
5
6
7
FROM alpine
...
COPY --from=0 /usr/local/go/lib/time/zoneinfo.zip /opt/zoneinfo.zip
ENV ZONEINFO /opt/zoneinfo.zip
OR
RUN apk --no-cache add tzdata
...

四種轉換時間格式範例程式:

diff
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package main

import (
"fmt"
"time"
)

func main() {
var Time int64
Time = 1619083664867 //ms->2021-04-22 17:27:44

t := time.Unix(0, Time*int64(time.Millisecond))
fmt.Println("case1: timestamp to time:", t)


layout1 := "2006-01-02T15:04:05"
fmt.Println("case2: Formatlayout1:", t.Format(layout1))

zone := time.FixedZone("", +0*60*60)
newTimezone0 := t.In(zone)
fmt.Println("case3: Timezone at +0:", newTimezone0.Format(layout1))

// name := "America/New_York"
name := "Asia/Taipei"
t, err := TimeIn(t, name)
if err != nil {
fmt.Println("err:", err)
}
fmt.Println("case4: Timezone at Taipei:", t.Format(layout1))

}
func TimeIn(t time.Time, name string) (time.Time, error) {
loc, err := time.LoadLocation(name)
if err == nil {
t = t.In(loc)
}
return t, err
}

轉換結果:

1
2
3
4
5
timestamp: 1619083664867
case1: timestamp to time: 2021-04-22 09:27:44.867 +0000 UTC
case2: Formatlayout1: 2021-04-22T09:27:44
case3: Timezone at +0: 2021-04-22T09:27:44
case4: Timezone at Taipei: 2021-04-22T17:27:44

網路參考文章

[Go 08] 認識時間格式與golang的時區轉換寫法

https://minilabmemo.github.io/2021/05/30/07-go-time/

作者

Mini Lab Memo

發表於

2021-05-30

更新於

2023-07-09

許可協議

評論