两个 time.Time 对象之间的差异

105

我对“Go”语言很陌生,问题可能很基础。

我有两个time.Time对象,我想以小时/分钟/秒为单位获取它们之间的差异。假设:

t1 = 2016-09-09 19:09:16 +0530 IST
t2 = 2016-09-09 19:09:16 +0530 IST
在上面的情况下,由于差异为0,它应该给我00:00:00。考虑另一种情况:
t1 = 2016-09-14 14:12:48 +0530 IST
t2 = 2016-09-14 14:18:29 +0530 IST
在这种情况下,差异将为00:05:41。 我查看了https://godoc.org/time,但无法理解其中的任何内容。
5个回答

154
你可以使用 Time.Sub() 函数来获取两个time.Time值之间的差异,结果将是一个time.Duration值。
当打印时,time.Duration会以“智能”的方式格式化自己。
t1 := time.Now()
t2 := t1.Add(time.Second * 341)

fmt.Println(t1)
fmt.Println(t2)

diff := t2.Sub(t1)
fmt.Println(diff)

输出:

2009-11-10 23:00:00 +0000 UTC
2009-11-10 23:05:41 +0000 UTC
5m41s

如果您想要时间格式为HH:mm:ss,您可以构建一个time.Time值并使用其Time.Format()方法,如下所示:

out := time.Time{}.Add(diff)
fmt.Println(out.Format("15:04:05"))

输出:

00:05:41

请在Go Playground上尝试这些示例。

当时间差小于一天时,这样做当然有效。如果时间差可能更大,则另说。结果必须包括天、月和年。复杂性大幅增加。有关详细信息,请参见此问题:

使用Golang中的time.Since()函数计算月份和年份

该文中介绍的解决方案通过显示带有以下签名的函数来解决此问题:

func diff(a, b time.Time) (year, month, day, hour, min, sec int)

即使您的时间在24小时内(此时yearmonthday将为0),您仍可使用它。


干得好!谢谢。 - Hemant Bhargava
如果我只需要小时或分钟,怎么样? - Hemant Bhargava
@HemantBhargava 然后使用不同的布局字符串,只包含小时和分钟:out.Format("15:04") - icza
这个不起作用。t1 := time.Now() t2 := t1.Add(time.Second * 34100)diff := t2.Sub(t1) fmt.Println(diff.Minutes())out := time.Time{}.Add(diff) fmt.Println(out.Format("15:30"))输出结果为: 568.3333333333334 09:90这并不正确。 - Hemant Bhargava
@HemantBhargava 当然是的,因为“15:30”是一个无效的格式字符串。请花些时间阅读Time.Format()上的文档,了解格式字符串的含义。使用out.Format("15:04:05")会输出正确的时间“09:28:20”。如果你只需要小时和分钟,则可以使用out.Format("15:04"),输出结果为“09:28”,你可以在Go Playground上查看这个例子。 - icza
这里列出了不同的格式:https://pkg.go.dev/time#pkg-constants - ufukty

39

实际上,time包的文档确实讨论了这个问题:

https://godoc.org/time#Time.Sub

https://godoc.org/time#Duration.Hours

你应该使用Sub()产生一个Duration对象,然后使用其中的Seconds(), Minutes(), Hours()方法之一。

package main

import (
        "fmt"
        "time"
)

func main() {
        t1 := time.Date(1984, time.November, 3, 13, 0, 0, 0, time.UTC)
        t2 := time.Date(1984, time.November, 3, 10, 0, 0, 0, time.UTC)
        fmt.Printf("The hours difference is: %f", t1.Sub(t2).Hours())
}

好的,谢谢您的快速回答。我已经这样做了:var duration time.Duration = trip.EndTime.Sub(trip.StartTime) fmt.Println("时间差:分钟", duration.Minutes(), "秒数:", duration.Seconds())但是似乎没有得到正确的数字。 - Hemant Bhargava
trip.EndTime\StartTime 是什么? - Shmulik Klein
抱歉!把它看作是:t1 = trip.StartTime t2 = trip.EndTime - Hemant Bhargava
实现了什么?在此期间除了以上两行代码,我没有写其他任何东西。 - Hemant Bhargava
就像我之前所说的,把trip.Starttime和trip.EndTime分别看作t1和t2。 - Hemant Bhargava
显示剩余3条评论

7

有两种常见的方法:

直接的方法:

startTime := time.Now()
diff := time.Now().Sub(startTime)

shorter one (a bit):

startTime := time.Now()
diff := time.Since(startTime)

4

除了Shmulik Klein的答案之外,还有一种计算time.Duration中不相交小时/分钟/秒的方法:

https://play.golang.org/p/VRoXG5NxLo

package main

import (
    "fmt"
    "math"
    "time"
)

func main() {
    t1 := time.Date(1984, time.November, 3, 13, 0, 0, 0, time.UTC)
    t2 := time.Date(1984, time.November, 3, 10, 23, 34, 0, time.UTC)

    hs := t1.Sub(t2).Hours()

    hs, mf := math.Modf(hs)
    ms := mf * 60

    ms, sf := math.Modf(ms)
    ss := sf * 60

    fmt.Println(hs, "hours", ms, "minutes", ss, "seconds")
}

2小时36分钟25.999999999999375秒

注:

  • 由于使用了float64类型,存在轻微的精度损失
  • 我们忽略了闰秒,并假设每分钟有60秒

4
闰秒考虑和数据类型考虑?这是一个$10问题的$1000答案... - jk-kim

0

演示


package main

import (
    "fmt"
    "math"
    "time"
)

func TimeAsString(dt float64) string {
    time := dt
    hours := math.Floor(time / 3600)
    minutes := math.Ceil(math.Mod(time, 3600)/60) - 1
    seconds := int(time) % 60
    return fmt.Sprintf("%v:%v:%v", hours, minutes, seconds)
}

func main() {
    mytime := 0.0
    last := time.Now()

    tick := time.Tick(33 * time.Millisecond)
    for {

        select {
        case <-tick:
            dt := time.Since(last).Seconds()
            last = time.Now()

            mytime += dt
            fmt.Println(TimeAsString(mytime))
        }

    }
}




网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接