[golang]在Go中處理時區

  • 2019 年 10 月 7 日
  • 筆記

 許多新手開發人員在處理時區時感到困惑。

  • 如何將它們存儲在資料庫中
  • 如何在Go中解析它們

當將時區存儲在資料庫中時,請始終遵循一個標準時區,理想的做法是保存UTC時間,並在顯示時區時根據需要將其轉化為各種時區。

以MYSQL作為存儲時間的示例

以下解決方案與DB無關。根據MySQL文檔,有兩種可以在MySQL存儲時間的方法。

  • DATETIME–DATETIME類型用於包含日期和時間部分的值。MYSQL檢索DATETIME並以'YYYY-MM-DD hh:mm:ss'格式顯示值。支援的範圍是'1000-01-01 00:00:00''9999-12-31 23:59:59'
  • TIMESTAMP-TIMESTAMP數據類型用於同時包含日期和時間部分的值。UTC TIMESTAMP的範圍是UTC。'1970-01-01 00:00:01''2038-01-19 03:14:07'。

在本文中,我將使用DATETIME為例。

現在,另一個也是最重要的事情是讀取並將其轉化為其他時區。

Go時間時區的轉換

下面的程式碼是展示我們如何在Go語言中做時區的轉換. 首先讓我們來定義地區和時區的的字典. 時區列表IANA時區標識可以從這裡得到Time Zones,

package main    import (      "fmt"      "errors"      "time"  )    type Country string    const (      Germany Country = "Germany"      UnitedStates Country  = "United States"      China Country = "China"    )    // timeZoneID 是國家=>IANA 標準時區標識符 的鍵值對字典  var timeZoneID = map[Country]string{      Germany:      "Europe/Berlin",      UnitedStates: "America/Los_Angeles",      China:   "Asia/Shanghai",  }    //獲取 IANA 時區標識符  func (c Country) TimeZoneID() (string, error) {      if id, ok := timeZoneID[c]; ok {          return id, nil      }      return "", errors.New("timezone id not found for country")  }    // 獲取tz時區標識符的格式化時間字元  func TimeIn(t time.Time, tz, format string) string {        // https:/golang.org/pkg/time/#LoadLocation loads location on      // 載入時區      loc, err := time.LoadLocation(tz)      if err != nil {          //handle error      }      // 獲取指定時區的格式化時間字元串      return t.In(loc).Format(format)  }    func main() {      // 獲取美國的時區結構體      tz, err := UnitedStates.TimeZoneID()      if err != nil {          //handle error      }      //格式化成美國的時區      usTime := TimeIn(time.Now(), tz, time.RFC3339)        fmt.Printf("Time in %s: %s",          UnitedStates,          usTime,      )  }

Go語言time.LoadLocation可能的坑

正如標準庫文檔中所說的:

The time zone database needed by LoadLocation may not be present on all systems, especially non-Unix systems. LoadLocation looks in the directory or uncompressed zip file named by the ZONEINFO environment variable, if any, then looks in known installation locations on Unix systems, and finally looks in $GOROOT/lib/time/zoneinfo.zip.

LoadLocation所需的時區資料庫可能並不存在於所有系統上,尤其是非unix系統. 如果有的話,LoadLocation查找由ZONEINFO環境變數命名的目錄或未壓縮的 ZONEINFO 環境變數命名的zip文件, 然後查找Unix系統上已知的安裝位置,最後查找 $GOROOT/lib/time/ ZONEINFO .zip.

Docker Go語言使用時區

默認的情況下時區資訊文件時在Go安裝的時候已經存在. 但是萬一你部署和編譯docker使用的時 multi-stage-docker Alpine 鏡像.你可以手動的使用一下命令來添加時區的數據.

RUN apk add tzdata

這將把時區資訊添加到 alpine 鏡像的 /usr/share/timezone. 但是也不要忘記設置環境變數 ZONEINFO 的值為 /usr/share/timezone

ZONEINFO=/usr/share/timezone

這裡有一個參考的示例 Dockerfile

FROM golang:1.12-alpine as build_base  RUN apk add --update bash make git  WORKDIR /go/src/github.com/your_repo/your_app/  ENv GO111MODULE on  COPY go.mod .  COPY go.sum .  RUN go mod download    FROM build_bash AS server_builder  COPY . ./  RUN GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o /go/bin/your_app    FROM alpine  RUN apk add tzdata    # 自定義運行階段的命令

示例

您可以在Go playground https://play.golang.org/p/UCKSpIWmiX7中查看完整示例