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

Ksh*_*shi 5 time go

我一直在尝试使用一些 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())))
}
Run Code Online (Sandbox Code Playgroud)

如果你在 Linux 或 Go Playground链接上运行它,你会得到Duration in seconds: 30预期的结果。

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

我已经为此纠结了好几个小时。对我可能缺少的东西有什么帮助吗?从那以后我唯一的线索是当 go 的time包去计算两个时间对象(time.Now()和我解析的时间对象)的秒数时,其中一个有属性hasMonotonic,一个没有,这导致 go 计算大不相同两秒钟。

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

Dan*_*tte 3

我想我已经弄清楚代码片段奇怪行为的原因是什么,并且可以提供解决方案。相关文档内容如下:

since返回自 t 以来经过的时间。它是 time.Now().Sub(t) 的简写。

但:

now返回当前本地时间。

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

一个适用于我的机器的解决方案(不过,给出一个操场示例可能没有多大意义):

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))
}
Run Code Online (Sandbox Code Playgroud)

输出:

duration in seconds: 14430
duration: 30s
Run Code Online (Sandbox Code Playgroud)