深圳幻海软件技术有限公司 欢迎您!

Go1.20 中两个关于 Time 的更新,终于不用背 2006-01-02 15:04:05 了!

2023-02-28

大家好,我是煎鱼。Go语言中有一个东西是比较有特色的,那就是time标准库,在各类与时间有关的场景都会常常用到,例如:定时/延迟任务、数据更新、时间比较。官方Demo是一个计算时间差的样例:复制import"time"funcmain(){start:=time.Now()time.Sleep(ti

大家好,我是煎鱼。

Go 语言中有一个东西是比较有特色的,那就是 time 标准库,在各类与时间有关的场景都会常常用到,例如:定时/延迟任务、数据更新、时间比较。

官方 Demo 是一个计算时间差的样例:

import "time"

func main() {
 start := time.Now()
 time.Sleep(time.Second)
 t := time.Now()
 elapsed := t.Sub(start)
 println(elapsed)
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

输出结果:

1000000000
  • 1.

神秘的 2006-01-02 15:04:05

在社区反馈中,更虎的是以下这个样例:

func main() {
 now := time.Now()
 v := now.Format("2006-01-02 15:04:05")
 println(v)
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

输出结果:

2009-11-10 23:00:00
  • 1.

这时候大家会遇到几个问题...最被常问的是 2006-01-02 15:04:05,这是随便写的时间点吗,甚至还曾经有传言说这是 Go 语言的诞生时间...

为什么是这个时间点

实际上 2006-01-02 15:04:05 是一个参考时间的格式,也就是其它语言中 Y-m-d H:i:s 格式,在功能上用于时间的格式化处理和规范。

那为什么是 2006-01-02 15:04:05 呢?其实这些 ”数字“ 是有意义的,每个布局字符串都是一个时间戳的表示,并非随便写的时间点。

可参见官方例子中的如下方式:

Jan 2 15:04:05 2006 MST
1   2  3  4  5    6  -7
  • 1.
  • 2.

我们也可以将其记忆为 2006 年 1 月 2 日 3 点 4 分 5 秒。

确实背不下来,快优化

虽然 Go 官方给出了一系列感觉很合理的解释,也通过上面的方式试图教会大家靠理解而不是靠纯背把这个时间点格式规范给记下来...

现实是很残酷的,母语不同,业务类型不同,不会经常用到 time 标准库,很容易忘记具体数值。

大佬也分析了 Go modules 上的所有模块代码,发现这个日期时间点,使用的次数非常高频:

排名

频率

格式

1

75616

time.RFC3339

2

23954

time.RFC3339Nano

3

13312

"2006-01-02 15:04:05"

4

12332

"2006-01-02"

5

11940

time.RFC1123

综上数据所述,终于在 Go 过去了 13 年后,将会在 Go1.20 增加如下三个常量:

DateTime   = "2006-01-02 15:04:05"
DateOnly   = "2006-01-02"
TimeOnly   = "15:04:05"
  • 1.
  • 2.
  • 3.

新版本中直接引用即可。

以后问这是什么意思的同学,可能会变少。

支持比较:Time.Compare

目前在标准库中,有 3 个方法来比较 time.Time 对象,分别是:Before()、Equal() 和 After(),作用上类似 <、== 和 >。但缺少 <= 和 >= 的等价物,因此在程序中实施起来会比较麻烦。

经常一番讨论,将会在 Go1.20 支持 Time.Compare,以此来达到类似的效果。作用是将 Time 对象 t 和 u 两者进行比较。

函数返回如下几种结果:

  • 如果 t 在 u 之前,则返回 -1。
  • 如果 t 在 u 之后,则返回 +1。
  • 如果它们相同,则返回 0。

源代码如下:

func (t Time) Compare(u Time) int {
 var tc, uc int64
 if t.wall&u.wall&hasMonotonic != 0 {
  tc, uc = t.ext, u.ext
 } else {
  tc, uc = t.sec(), u.sec()
  if tc == uc {
   tc, uc = int64(t.nsec()), int64(u.nsec())
  }
 }
 switch {
 case tc < uc:
  return -1
 case tc > uc:
  return +1
 }
 return 0
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

函数内部比较简单。

总结

Go Time 一直都是话题榜上的老面孔。这一次在 Go1.20 的新特性中,对 2006-01-02 15:04:05 常用的时间点进行了常量声明,便于我们后续直接引用,不用 “死记硬背”。

在 Time 对象的比较上,也补全了 Compare 方法,便于两个时间对象之前之后的对比。

Go1.20 将在明年 2023 年 2,3 月份左右就可以见到了。11 月底会发预览版本。冲不?