Golang中使用time.Parse和time.Sub解析时间间隔
Golang中使用time.Parse和time.Sub解析时间间隔 我需要解析格式为 HH:MM:SS 的 time.Duration。
使用 time.Parse("15:04:05", stringToParse) 来解析非常方便,但之后我需要获取持续时间。为此有另一个方便的方法 time.Sub。
所以基本上这段代码应该能工作:
func parseDur(s string) time.Duration {
t, _ := time.Parse("15:04:05", o)
return t.Sub(time.Time{})
}
但是这段代码返回的解析后持续时间是 -1 年。我可以通过返回以下内容来修复它:
t.AddDate(1, 0, 0).Sub(time.Time{})
但这看起来太丑了!
看起来 time.Time{} 返回的是
0001-01-01 00:00:00 +0000 UTC
但是 time.Parse() 默认返回的是
0000-01-01 00:00:00 +0000 UTC
这不是设计缺陷吗?应该修复吗?
更多关于Golang中使用time.Parse和time.Sub解析时间间隔的实战教程也可以访问 https://www.itying.com/category-94-b0.html
感谢您为这个问题提供的出色解决方案!在我看来,第一个方案似乎更优雅。
我知道时间的零值是 UTC 时间 1 年 1 月 1 日 00:00:00.000000000,但为什么 time.Parse 的返回值不是基于这个零值呢?
更多关于Golang中使用time.Parse和time.Sub解析时间间隔的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
GRbit:
这不是设计缺陷吗?
不是
Time类型的零值是公元1年1月1日 00:00:00.000000000 UTC。由于这个时间在实际中不太可能出现,IsZero方法提供了一种简单的方式来检测一个时间是否未被显式初始化。
package main
import (
"fmt"
"time"
)
const clockLayout = "15:04:05"
var clockZero, _ = time.Parse(clockLayout, "00:00:00")
func clockDuration(clock string) (time.Duration, error) {
c, err := time.Parse(clockLayout, clock)
if err != nil {
return 0, err
}
return c.Sub(clockZero), nil
}
func main() {
d, err := clockDuration("01:02:03")
fmt.Println(d, err)
}
1h2m3s <nil>
package main
import (
"fmt"
"time"
)
func clockDuration(clock string) (time.Duration, error) {
c, err := time.Parse("15:04:05", clock)
if err != nil {
return 0, err
}
h, m, s := c.Clock()
d := time.Duration(h)*time.Hour +
time.Duration(m)*time.Minute +
time.Duration(s)*time.Second
return d, nil
}
func main() {
d, err := clockDuration("01:02:03")
fmt.Println(d, err)
}
1h2m3s <nil>
这是一个常见的问题,根源在于 time.Parse 的默认日期处理方式。time.Parse 在解析不包含日期部分的时间字符串时,会使用默认的日期 0000-01-01(公元0年1月1日),而 time.Time{} 的零值日期是 0001-01-01(公元1年1月1日)。两者相差1年,导致 Sub 计算出的持续时间为负值。
这不是设计缺陷,而是 time.Parse 的预期行为。更简洁的解决方案是使用 time.ParseDuration 解析标准格式,或者手动解析 HH:MM:SS 格式并计算持续时间。
以下是两种推荐方案:
方案1:手动解析并计算持续时间(适用于 HH:MM:SS 格式)
func parseDur(s string) (time.Duration, error) {
var h, m, sec int
_, err := fmt.Sscanf(s, "%d:%d:%d", &h, &m, &sec)
if err != nil {
return 0, err
}
return time.Duration(h)*time.Hour + time.Duration(m)*time.Minute + time.Duration(sec)*time.Second, nil
}
方案2:使用 time.Parse 并校正基准时间
func parseDur(s string) (time.Duration, error) {
t, err := time.Parse("15:04:05", s)
if err != nil {
return 0, err
}
// 使用与 Parse 相同的基准日期进行计算
base := time.Date(0, 1, 1, 0, 0, 0, 0, time.UTC)
return t.Sub(base), nil
}
方案3:如果输入是标准持续时间格式,直接使用 time.ParseDuration
// 注意:这要求输入格式为 "1h2m3s" 而非 "01:02:03"
dur, err := time.ParseDuration("1h30m45s")
第一种方案最直接,避免了日期基准不一致的问题。第二种方案明确了基准时间,使逻辑更清晰。根据你的具体需求选择即可。



