time.Sub() returns 1 秒尽管相差超过几年

time.Sub() returns 1 second despite the difference exceeding couple of years

我正在尝试编写一段代码来响应由于同步而导致的系统时间变化。这是 goroutine 中 运行 的一个相当简单的代码:

var start, end time.Time
var start_ts, end_ts int64
var diff_ts time.Duration
var diff time.Duration

for {
    start = time.Now()
    start_ts = start.Unix()
    fmt.Printf("Now: => %v (%d);\n", start, start_ts)
    time.Sleep(1 * time.Second)
    end = time.Now()
    end_ts = end.Unix()
    fmt.Printf("New Now: %v (%d);\n", end, end_ts)
    diff = end.Sub(start)
    diff_ts = time.Duration(end_ts-start_ts) * time.Second
    fmt.Printf("Measured time duration: %v (%v) %f (%f)\n", diff, diff_ts, diff.Seconds(), diff_ts.Seconds())
}

我的问题是,当我在另一个控制台中更改系统时间时,时间被正确读取,但是 "original" 时差不正确,我不得不求助于手动构建时差。这是日志的摘录:

Now: => 2020-02-26 12:29:42.778827718 +0000 UTC m=+21.776791756 (1582720182);
New Now: 2017-01-01 01:02:03.391215325 +0000 UTC m=+22.777003266 (1483232523);
Measured time duration: 1.00021151s (-27635h27m39s) 1.000212 (-99487659.000000)

为什么 diff 对象 returns 1 秒,即使差异明显大于那个?

go 的时间包同时使用了 "wall clock"(你想要改变的)和单调时钟。来自 docs:

Operating systems provide both a “wall clock,” which is subject to changes for clock synchronization, and a “monotonic clock,” which is not. The general rule is that the wall clock is for telling time and the monotonic clock is for measuring time. Rather than split the API, in this package the Time returned by time.Now contains both a wall clock reading and a monotonic clock reading; later time-telling operations use the wall clock reading, but later time-measuring operations, specifically comparisons and subtractions, use the monotonic clock reading.

[...]

If Times t and u both contain monotonic clock readings, the operations t.After(u), t.Before(u), t.Equal(u), and t.Sub(u) are carried out using the monotonic clock readings alone, ignoring the wall clock readings.

这是专门为防止发生时钟同步(ntp 等)(并将时钟向后推)时的异常应用程序行为而设计的。 go 的时间包确保单调时钟读数始终向前移动(当比较或减法操作时)。