时间系统在Go中的使用

409 阅读2分钟

概述

无论在什么领域,都可能遇到处理时间的问题。掌握时间系统,需要理解2个问题:1.时区的字符串规范;2.编程语言怎么处理时间?

正文

时区的字符串规范

带时区的时间表示是有规范的,常用的就是Go的time包中的RFC3339,他的例子如下: 2022-02-09T20:36:42Z2022-02-10T04:36:42+08:00。除此之外,很多开源软件用RFC3339Nano标准,相比于RFC3339精度更高,例如2022-02-09T20:36:42.123456Z

Go 用time.Location表示时区: loca, err := time.LoadLocation("Asia/Shanghai")

Go语言如何处理时间

对于任何一种编程语言,时间有3种存在的类型,他们之间可以随意转换:

  1. string
  2. Time 类型
  3. Unix时间(一个整数,从1970-01-01T00:00:00Z开始的秒数)

转到Time

func ExampleToTime() {
    t, err := time.Parse(time.RFC3339, str)
    // ...
    t := time.Unix(int64(i), 0)
}

转到string

func ExampleToString() {
    utc := time.Now().UTC().Format(time.RFC3339)
    local := time.Now().Local().Format(time.RFC3339)
    in := time.Now().In(location).Format(time.RFC3339)
}

转到unix时间戳

func ExampleToUnix() {
    unix := time.Now().Unix()
}

时间如何加减,如何求间隔

Go 使用 time.Duration类型

// 加减都用Add
t1 := t.Add(time.hour)
t2 := t.Add(-time.hour)

// 间隔用Sub
duration := t.Sub(lastTime)

容易忽略的坑

时区一致性

Time类型里有一个时区状态的,可以把同一个t在任意时区内转换,因此如果输出字符串会丢失时区信息,要注意前后的一致性

t, _ := time.Parse(time.RFC3339, "2022-04-01T20:36:42Z")
localT := t.Local()
str := localT.Format("2006-01-02")

输出的date不是2022-04-01,而是2号,因为localT在东八区

后端存储时间怎么选

  1. 统一用UTC时间的字符串(可以满足字典序)
  2. 统一用Unix时间戳 需要前端展示的时候在转化为需要的时区。例如Kubernetes存储时间时用的就是封装的Time类型,时区在UTC。