翻译下 golang package time

时间:2022-10-18 08:03:59

# 关于 `package time`

个人体会:"wall clock" 可以理解为就是实际的时钟,而 "monotonic clock" 则是程序内部的时钟。
所以前者是用来获取具体的时间,后者是用来计时的。
ps: 原文都是用 "monotonic clock reading",含意很明显,就是读取时间。

## 总览

`package time` 提供了用于测量和显示时间的功能。
日历的计算,总是假定Gregorian日历 - 无闰秒。

## Monotonic Clocks

操作系统同时提供了 "wall clock" 和 "monotonic clock",前者用于时钟的同步,后者不是。
通用的做法是,"wall clock" 用于获取时间,而 "monotonic clock" 则用于测量时间。
`time.Now()` 同时包含了 "wall clock" 和 "monotonic clock",想要读取时间,就使用前者,想要测量时间、特殊的对比和相减,就使用后者。

例如,下面的代码是计算代码的执行耗时,大约总是20ms,无论 "wall clock"怎么改变:
```golang
package time

start := time.Now()
//... operation that takes 20 milliseconds ...
t := time.Now()
elapsed := t.Sub(start)
```

在其他情况里,例如 `time.Since(start)`、`time.Until(deadline)`以及`time.Now().Before(deadline)`,都是类似的,都与 "wall clock" 的改变无关。

本节的剩余部分给出了如何使用"monotonic clock"的细节,但是,使用本package无需理解这些细节。

`time.Now()` 返回的 `Time`,包含了一个 `monotonic clock`。 而,如果 `Time t` 包含一个 "monotonic clock",那 `t.Add` 就可以同时给 "wall clock"和"monotonic clock"增加 duration - 以便计算结果。 因为 `t.AddDate(y, m, d)`、`t.Round(d)`和`t.Truncate(d)` 都是 "wall time"的计算,它们会从结果中去掉所有的 "monotonic clock"。因为 `t.In`、`t.Local`和`t.UTC` 都是使用它们的 "wall time" 结果,所以它们也会从结果中去掉所有的 "monotonic clock"。
去掉 "monotonic clock" 的权威做法是 `t = t.Round(0)`。

如果 `Time t`和 `Time u` 都包含 "monotonic clock",那么操作 `t.After(u)`、`t.Before(u)`、`t.Equal(u)`以及`t.Sub(u)` 仅仅会使用 "monotonic clock",而忽略掉 "wall clock"。如果 `t`或`u` 有一个不包含 "monotonic clock",这些操作才会使用 "wall clock"。

在一些系统中,当计算机休眠的时候,"monotonic clock"会停止。在这种系统上,`t.Sub(u)`可能不会精确地反映`t`和`u`之间的时间。

因为 "monotonic clock" 的意义仅限于当前进程,所以由`t.GobEncode`、`t.MarshalBinary`、`t.MarshalJSON`和`t.MarshalText`序列化得到的内容会忽略掉 "monotonic clock",且 `t.Format` 也没有提供相应的格式化。
类似地,使用 `time.Date`、`time.Parse`、`time.ParseInLocation`、`time.Unix`来构造,以及通过反序列化 `t.GobDecode`、`t.UnmarshalBinary`、`t.UnmarshalJSON`、`t.UnmarshalText`得到的时间,也不会包含 "monotonic clock" 。

注意,Go的 `==` 操作符,不仅会比较时间的`instant`,还会比较`Location`以及 "monotonic clock"。详见 Time类型的文档,那里有一个相等性测试的讨论。

为了调试方便,`t.String`包含了 "monotonic clock" - 如果存在的话。 如果 `t !=u ` 是因为不同的 "monotonic clock" 的话,可以通过 `t.String` 和 `u.String` 清楚地看到区别。