概述
无论在什么领域,都可能遇到处理时间的问题。掌握时间系统,需要理解2个问题:1.时区的字符串规范;2.编程语言怎么处理时间?
正文
时区的字符串规范
带时区的时间表示是有规范的,常用的就是Go的time包中的RFC3339,他的例子如下:
2022-02-09T20:36:42Z,2022-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种存在的类型,他们之间可以随意转换:
- string
- Time 类型
- 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在东八区
后端存储时间怎么选
- 统一用UTC时间的字符串(可以满足字典序)
- 统一用Unix时间戳 需要前端展示的时候在转化为需要的时区。例如Kubernetes存储时间时用的就是封装的Time类型,时区在UTC。