Golang中time包的bug问题求助
Golang中time包的bug问题求助
package main
import (
"fmt"
"time"
)
func main() {
FORMAT := "2006-01-02 15:04:05"
a := time.Now()
fmt.Println("Now:", time.Now().Format(FORMAT))
fmt.Println("A:", a.Format(FORMAT), a.Unix(), a.UnixNano())
fmt.Println("\nSleep...\n")
time.Sleep(time.Second * 10)
fmt.Println("Now:", time.Now().Format(FORMAT))
b := a.Add(5 * time.Hour)
c := time.Now()
fmt.Println("B:", b.Format(FORMAT), b.Unix(), b.UnixNano())
fmt.Println("C:", c.Format(FORMAT), c.Unix(), c.UnixNano())
if b.After(c) {
fmt.Println("After,B after C")
} else {
fmt.Println("After,B is not after C")
}
if b.Unix() >= c.Unix() {
fmt.Println("Unix,B after C")
} else {
fmt.Println("Unix,B is not after C")
}
if b.UnixNano() >= c.UnixNano() {
fmt.Println("UnixNano,B after C")
} else {
fmt.Println("UnixNano,B is not after C")
}
}

Go版本: go version go1.14.1 windows/amd64 go version go1.15.6 windows/amd64
在程序休眠期间,修改系统时间(增加一天),After 函数返回了 true?
这是为什么?
更多关于Golang中time包的bug问题求助的实战教程也可以访问 https://www.itying.com/category-94-b0.html
好的,所以我需要使用 Round 函数,时间比较才会正确吗?
当代码运行到 time.Sleep(time.Second * 10) 时,修改你的操作系统时间(增加一天)。
我需要使用 ‘Round’ 函数,时间比较会正确吗?
剥离单调时钟读数的规范方法是使用 t = t.Round(0)。
这将确保时间是挂钟(系统)时间。
hollowaykeanho:
未知原因
已知原因:时间包:单调时钟。
hollowaykeanho:
看起来像是一个错误。你能通过发送电子邮件到 https://groups.google.com/g/golang-nuts 联系开发者吗?
请不要这样做。阅读时间包:单调时钟。
当代码运行到
time.Sleep(time.Second * 10)时,修改你的操作系统时间(增加一天)。
我之前没有意识到挂钟时间增加了。那样的话,@petrus 是对的。挂钟和单调时钟之间存在差异。
我过于关注操作系统的差异,没有注意到这里有一个调整。
编辑:抱歉,刚才出去吃饭了。
GahdWu:
在休眠期间修改系统时间(增加一天),
After函数会返回 true 吗?
这看起来像是一个错误。你可以通过发送邮件到 https://groups.google.com/g/golang-nuts 联系开发者。
我在 Debian amd64 上无法复现你的问题。
u0:test$ go run main.go
Now: 2020-12-10 18:12:28
A: 2020-12-10 18:12:28 1607595148 1607595148476836765
Sleep...
Now: 2020-12-10 18:12:38
B: 2020-12-10 23:12:28 1607613148 1607613148476836765
C: 2020-12-10 18:12:38 1607595158 1607595158477300968
After,B after C
Unix,B after C
UnixNano,B after C
u0:test$ go run main.go
Now: 2020-12-10 18:12:40
A: 2020-12-10 18:12:40 1607595160 1607595160732716728
Sleep...
Now: 2020-12-10 18:12:50
B: 2020-12-10 23:12:40 1607613160 1607613160732716728
C: 2020-12-10 18:12:50 1607595170 1607595170733191244
After,B after C
Unix,B after C
UnixNano,B after C
在 go version go1.15.2 linux/amd64 环境下。
GahdWu:
为什么?
显然,在你的第二次执行中,未知原因导致 C 的 Unix 格式时间表现异常。该值应该更接近 A,而不是 B。
根据你提供的代码和描述,这不是Go语言time包的bug,而是系统时间修改导致的预期行为。
time.Now() 获取的是当前系统时间,而 a.Add() 是基于 a 的时间值进行计算。当你修改系统时间后,c := time.Now() 获取的是修改后的新时间,而 b := a.Add(5 * time.Hour) 仍然基于修改前的 a 进行计算。
示例重现:
package main
import (
"fmt"
"time"
)
func main() {
// 记录初始时间
now := time.Now()
fmt.Printf("初始时间: %v\n", now.Format("2006-01-02 15:04:05"))
// 模拟5小时后
future := now.Add(5 * time.Hour)
fmt.Printf("5小时后: %v\n", future.Format("2006-01-02 15:04:05"))
// 假设此时系统时间被向前调整了24小时
// 实际环境中是通过修改系统时钟实现的
adjustedNow := now.Add(24 * time.Hour) // 模拟时间调整
fmt.Printf("调整后当前时间: %v\n", adjustedNow.Format("2006-01-02 15:04:05"))
// 比较
fmt.Printf("future.After(adjustedNow): %v\n", future.After(adjustedNow))
fmt.Printf("future.Unix() >= adjustedNow.Unix(): %v\n",
future.Unix() >= adjustedNow.Unix())
}
输出结果会显示 future.After(adjustedNow) 返回 false,因为调整后的时间已经超过了 future。
关键点:
time.Time值是不可变的,a.Add()返回新的时间值After()方法比较的是两个time.Time值的内在时间戳- 修改系统时间会影响后续
time.Now()的返回值 - 所有比较方法(
After、Before、Equal)和Unix时间戳比较的结果应该一致
如果你需要不受系统时间修改影响的时间计算,可以考虑使用 time.Since() 或单调时钟:
package main
import (
"fmt"
"time"
)
func main() {
start := time.Now()
// 使用单调时钟计算经过的时间
time.Sleep(2 * time.Second)
elapsed := time.Since(start) // 不受系统时间修改影响
fmt.Printf("实际经过时间: %v\n", elapsed)
// 基于单调时钟的未来时间点
future := start.Add(5 * time.Hour)
actualFuture := start.Add(elapsed).Add(5 * time.Hour)
fmt.Printf("理论未来时间: %v\n", future.Format("15:04:05"))
fmt.Printf("实际未来时间: %v\n", actualFuture.Format("15:04:05"))
}
在时间敏感的应用中,建议使用单调时钟进行持续时间计算,使用系统时钟进行绝对时间显示。
为什么?
单调时钟与挂钟时钟的区别。请阅读 time 包:单调时钟。
使用以下版本的代码运行你的测试,并以文本形式(而非图片)发布你的输出。
package main
import (
"fmt"
"time"
)
func main() {
FORMAT := "2006-01-02 15:04:05"
a := time.Now()
fmt.Println("Now:", time.Now().Format(FORMAT))
fmt.Println("A:", a.Format(FORMAT), a.Unix(), a.UnixNano())
fmt.Println("\nSleep...\n")
time.Sleep(time.Second * 10)
fmt.Println("Now:", time.Now().Format(FORMAT))
b := a.Add(5 * time.Hour)
c := time.Now()
fmt.Println("B:", b.Format(FORMAT), b.Unix(), b.UnixNano())
fmt.Println("C:", c.Format(FORMAT), c.Unix(), c.UnixNano())
fmt.Println()
fmt.Println("Monotonic Clock (m):")
fmt.Println("A:", a)
fmt.Println("B:", b)
fmt.Println("C:", c)
fmt.Println("B after C:", b.After(c))
fmt.Println("Wall Clock:")
fmt.Println("A:", a.Round(0))
fmt.Println("B:", b.Round(0))
fmt.Println("C:", c.Round(0))
fmt.Println("B after C:", b.Round(0).After(c.Round(0)))
fmt.Println()
fmt.Println("Monotonic Clock")
if b.After(c) {
fmt.Println("After,B after C")
} else {
fmt.Println("After,B is not after C")
}
fmt.Println("Wall Clock")
if b.Unix() >= c.Unix() {
fmt.Println("Unix,B after C")
} else {
fmt.Println("Unix,B is not after C")
}
fmt.Println("Wall Clock")
if b.UnixNano() >= c.UnixNano() {
fmt.Println("UnixNano,B after C")
} else {
fmt.Println("UnixNano,B is not after C")
}
}
.
Monotonic Clock (m):
A: 2020-12-10 06:53:48.766741505 -0500 EST m=+0.000081695
B: 2020-12-10 11:53:48.766741505 -0500 EST m=+18000.000081695
C: 2020-12-10 06:53:58.776090071 -0500 EST m=+10.009429982
B after C: true
Wall Clock:
A: 2020-12-10 06:53:48.766741505 -0500 EST
B: 2020-12-10 11:53:48.766741505 -0500 EST
C: 2020-12-10 06:53:58.776090071 -0500 EST
B after C: true
Monotonic Clock
After,B after C
Wall Clock
Unix,B after C
Wall Clock
UnixNano,B after C

