go - 为什么 time.Since 在 Windows 上返回负持续时间?

标签 go time

我一直在尝试使用 go,并在 windows 上发现了一些奇怪的行为。如果我通过解析特定格式的时间字符串构造时间对象,然后使用 time.Since() 等函数,我会得到负持续时间。

代码示例:

package main

import (
    "fmt"
    "time"
    "strconv"
)

func convertToTimeObject(dateStr string) time.Time {
    layout := "2006-01-02T15:04:05.000Z"
    t, _:= time.Parse(layout, dateStr)

    return t
}

func main() {
    timeOlder := convertToTimeObject(time.Now().Add(-30*time.Second).Format("2006-01-02T15:04:05.000Z"))
    duration := time.Since(timeOlder)
    fmt.Println("Duration in seconds: " + strconv.Itoa(int(duration.Seconds())))
}

如果您在 Linux 或 Go Playground 上运行它 link ,您得到的结果为 Duration in seconds: 30,这是预期的。

但是,在 Windows 上,使用 Go 1.10.3 运行同一段代码会得到 Duration in seconds: -19769

我已经为此苦苦思索了几个小时。对我可能遗漏的东西有什么帮助吗? 从现在开始我唯一的线索是,当 go 的 time 包去计算两个时间对象(time.Now() 和我解析的时间对象)的秒数时,其中一个具有 hasMonotonic 属性,而另一个没有,这导致两者计算的秒数大不相同。

我不是时间方面的专家,所以希望得到一些帮助。我本来打算为 Go 提交一个错误,但想在这里向专家询问是否有明显的我可能遗漏的东西。

最佳答案

我想我弄清楚了您的代码片段出现奇怪行为的原因,并且可以提供解决方案。相关docs阅读如下:

since returns the time elapsed since t. It is shorthand for time.Now().Sub(t).

但是:

now returns the current local time.

这意味着您正在格式化 timeOlder 并从未格式化的本地时间中减去它。这当然会导致意外行为。一个简单的解决方案是根据您的格式解析本地时间,然后再从中减去 timeOlder

一个在我的机器上运行的解决方案(尽管给出一个 playground 示例可能没有多大意义):

func convertToTimeObject(dateStr string) time.Time {
    layout := "2006-01-02T15:04:05.000Z"
    t, err := time.Parse(layout, dateStr)
    // check the error!
    if err != nil {
        log.Fatalf("error while parsing time: %s\n", err)
    }
    return t
}

func main() {
    timeOlder := convertToTimeObject(time.Now().Add(-30 * time.Second).Format("2006-01-02T15:04:05.000Z"))
    duration := time.Since(timeOlder)

    // replace time.Since() with a correctly parsed time.Now(), because
    // time.Since() returns the time elapsed since the current LOCAL time.
    t := time.Now().Format("2006-01-02T15:04:05.000Z")
    timeNow := convertToTimeObject(t)

    // print the different results
    fmt.Println("duration in seconds:", strconv.Itoa(int(duration.Seconds())))
    fmt.Printf("duration: %v\n", timeNow.Sub(timeOlder))
}

输出:

duration in seconds: 14430
duration: 30s

关于go - 为什么 time.Since 在 Windows 上返回负持续时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50970900/

相关文章:

go - InDelta 和 InEpsilon 之间的区别

go - filepath.Join 删除点

gorm golang one2many 同一张表

c# - 如何在 C# 中将 Int 转换为时间?

javascript - 使用 moment().utcOffset() 更新时间偏移

ruby - 将字符串转换为日期时间

pointers - 如何修改嵌套结构的属性值

Golang - 管道到外部执行

time - 我如何在 Go 语言中格式化时间

python - 显示 pygtk 小部件后 5 秒运行函数