作为程序员,我们经常需要对时间进行处理。在 Go 中,标准库 time 提供了对应的能力。
本文将介绍 time 库中一些重要的函数和方法,希望能帮助到那些一遇到 Go 时间处理问题就需要百度的童鞋。
应对时区问题
在编程中,我们经常会遭遇八小时时间差问题。这是由时区差异引起的,为了能更好地解决它们,我们需要理解几个时间定义标准。
GMT(Greenwich Mean Time),格林威治平时。GMT 根据地球的自转和公转来计算时间,它规定太阳每天经过位于英国伦敦郊区的皇家格林威治天文台的时间为中午12点。GMT 是前世界标准时。
UTC(Coordinated Universal Time),协调世界时。UTC 比 GMT 更精准,它根据原子钟来计算时间。在不需要精确到秒的情况下,可以认为 UTC=GMT。UTC 是现世界标准时。
从格林威治本初子午线起,往东为正,往西为负,全球共划分为 24 个标准时区,相邻时区相差一个小时。
package main import ( "fmt" "time" ) func main() { fmt.Println(time.Now()) }
中国大陆使用的是东八时区的标准时,即北京时间 CST,China Standard Time。
$ go run main.go 2022-07-17 16:37:31.186043 +0800 CST m=+0.000066647
这是默认时区下的结果,time.Now()的打印中会标注+0800 CST。
假设我们是在美国洛杉矶时区下,那得到的结果是什么呢?
$ TZ="America/Los_Angeles" go run main.go 2022-07-17 01:39:12.391505 -0700 PDT m=+0.000069514
可以看到,此时的结果是-0700 PDT 时间,即 PDT(Pacific Daylight Time)太平洋夏季时间。由于时区差异,两次执行的时间结果相差了 15 小时。
注意,在使用 Docker 容器时,系统默认的时区就是 UTC 时间(0 时区),和我们实际需要的北京时间相差八个小时,这是导致八小时时间差问题的经典场景。
时区问题的应对策略,可以详细查看 src/time/zoneinfo_unix.go 中 initLocal() 函数的加载逻辑。例如,可以通过指定环境变量 TZ,修改/etc/localtime文件等方式来解决。
因为时区问题非常重要,所以放在了文章第一部分讲述。下面开始介绍 time 库的使用。
时间瞬间 time.Time
time 库,最核心的对象是 time.Time 结构体。它的定义如下,用以表示某个瞬间的时间。
type Time struct { // wall and ext encode the wall time seconds, wall time nanoseconds, // and optional monotonic clock reading in nanoseconds. wall uint64 ext int64 loc *Location }
计算机在时间处理上,主要涉及到两种时钟。
- 墙上时钟(wall time),又称为钟表时间,用于表示具体的日期与时间。
- 单调时钟(monotonic clocks),总是保证时间是向前的,不会出现墙上时钟的回拨问题,因此它很适合用于测量持续时间段。