许多新手开发人员在处理时区时感到困惑。

  • 如何将它们存储在数据库中
  • 如何在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可能的坑

正如标准库文档中所说的:

LoadLocation所需的时区数据库可能并不存在于所有系统上,尤其是非unix系统. 如果有的话,LoadLocation查找由ZONEINFO环境变量命名的目录或未压缩的 ZONEINFO 环境变量命名的zip文件, 然后查找Unix系统上已知的安装位置,最后查找 $GOROOT/lib/time/ ZONEINFO .zip.

Docker Go语言使用时区

默认的情况下时区信息文件时在Go安装的时候已经存在. 但是万一你部署和编译docker使用的时 multi-stage-docker Alpine 镜像.你可以手动的使用一下命令来添加时区的数据.

这将把时区信息添加到 alpine 镜像的 /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中查看完整示例

01-14 20:50