引入
json 包 解码数据时常遇到时间字段,日志记录、定时任务、性能测量也都离不开时间。Go 的 time 包提供时间的创建、格式化、运算和定时功能,是日常开发中用得最多的标准库之一。
正文
定义
定义
time包提供时间处理功能,包括获取当前时间、创建时间点、格式化与解析、计算时间差、定时器和周期定时器。Go 的时间格式化使用固定的参考时间而非格式化字符串。
语法
import "time"
now := time.Now() // 当前时间
t := time.Date(2026, 7, 20, 15, 0, 0, 0, time.UTC) // 指定时间
duration := t.Sub(now) // 时间差
str := t.Format("2006-01-02 15:04:05") // 格式化例子
获取当前时间
now := time.Now()
fmt.Println(now.Year()) // 2026
fmt.Println(now.Month()) // July
fmt.Println(now.Day()) // 20
fmt.Println(now.Hour()) // 15
fmt.Println(now.Minute()) // 30
fmt.Println(now.Second()) // 0time.Now() 返回当前本地时间。通过方法可以取出年、月、日、时、分、秒各个分量。
创建指定时间
t := time.Date(2026, 7, 20, 15, 30, 0, 0, time.UTC)
fmt.Println(t) // 2026-07-20 15:30:00 +0000 UTC
// 使用本地时区
t2 := time.Date(2026, 7, 20, 15, 30, 0, 0, time.Local)time.Date 创建指定时间点,参数依次是年、月、日、时、分、秒、纳秒、时区。
格式化时间
t := time.Date(2026, 7, 20, 15, 30, 0, 0, time.UTC)
fmt.Println(t.Format("2006-01-02 15:04:05")) // 2026-07-20 15:30:00
fmt.Println(t.Format("2006/01/02")) // 2026/07/20
fmt.Println(t.Format("15:04:05")) // 15:30:00
fmt.Println(t.Format(time.RFC3339)) // 2026-07-20T15:30:00ZGo 的格式化不用 %Y%m%d 这种占位符,而是用固定参考时间 2006-01-02 15:04:05(即 Unix 时间 1136239445)。记住这个参考时间就掌握了格式化。
解析时间字符串
layout := "2006-01-02 15:04:05"
value := "2026-07-20 15:30:00"
t, err := time.Parse(layout, value)
if err != nil {
log.Fatal(err)
}
fmt.Println(t.Year(), t.Month(), t.Day()) // 2026 July 20time.Parse 用同样的参考时间布局把字符串解析为 time.Time。
时间差
start := time.Now()
time.Sleep(2 * time.Second)
end := time.Now()
diff := end.Sub(start)
fmt.Println(diff) // 2.000...s
fmt.Println(diff.Seconds()) // 2.000...
fmt.Println(diff.Milliseconds()) // 2000...Sub 返回 time.Duration 类型,表示两个时间点之间的间隔。Duration 可以调用 Seconds()、Milliseconds() 等方法转换单位。
时间加减
now := time.Now()
tomorrow := now.Add(24 * time.Hour)
lastWeek := now.AddDate(0, 0, -7)
fmt.Println(tomorrow)
fmt.Println(lastWeek)Add 加上一个 Duration,AddDate 按年月日加。Before() 和 After() 比较时间先后。
定时器 Timer
timer := time.NewTimer(3 * time.Second)
<-timer.C
fmt.Println("3 秒到了")NewTimer 创建一个一次性定时器,到时后往通道 C 发送当前时间。用 <-timer.C 阻塞等待。
周期定时器 Ticker
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
for i := 0; i < 5; i++ {
<-ticker.C
fmt.Println("tick", i)
}NewTicker 创建一个周期性定时器,每隔指定时间往通道发一次信号。用完要 Stop() 释放资源。
Sleep
fmt.Println("开始")
time.Sleep(2 * time.Second)
fmt.Println("2 秒后")time.Sleep 让当前 goroutine 暂停指定时长。简单直接,但不适合精确计时。
常见写法
| 写法 | 说明 |
|---|---|
time.Now() | 获取当前时间 |
time.Date(y, m, d, h, min, s, ns, loc) | 创建指定时间 |
t.Format("2006-01-02 15:04:05") | 格式化时间 |
time.Parse(layout, value) | 解析时间字符串 |
t.Sub(t2) | 计算时间差 |
t.Add(d) | 时间加一个 Duration |
t.AddDate(y, m, d) | 时间加年月日 |
t.Before(t2) / t.After(t2) | 比较时间 |
time.Sleep(d) | 暂停指定时长 |
time.NewTimer(d) | 一次性定时器 |
time.NewTicker(d) | 周期性定时器 |
time.Since(t) | 从 t 到现在的时间差 |
特点
- Go 格式化用固定参考时间
2006-01-02 15:04:05,不是%Y那种占位符 time.Duration底层是int64纳秒,精度到纳秒Timer一次性触发,Ticker周期性触发,底层都是通道通信Ticker用完必须Stop(),否则** goroutine 泄漏**time.Since(t)等价于time.Now().Sub(t),测量耗时最常用- 时区用
time.UTC或time.Local,生产环境建议统一用 UTC
理解
time 包的核心就三个东西:Time(时间点)、Duration(时间间隔)、格式化布局。格式化记住那个神奇的 2006-01-02 15:04:05 就行,所有格式都从这个参考时间变出来。Timer 和 Ticker 配合通道使用,在并发编程和定时任务里非常好使。time.Since 一行就能测耗时,写性能日志离不开它。
引出
time 包能记录时间点,但如果有一批时间数据要按先后排列,就需要排序能力。接下来看 Go sort 包,学习怎么对切片进行排序。