首页 / Go 语言入门教程 / time 包

Go 语言入门教程

time 包

本教程共 80 篇 · 第 74 篇 · 更新于 2026-07-27 · 约 8 分钟阅读

GoGo 入门教程timeDurationTickerTimer格式化时区

74. time 包

本节目标:掌握 time.Time 和 time.Duration,学会格式化时间的「模板」写法,用好 Ticker 和 Timer,理解时区处理。

获取当前时间

now := time.Now()
fmt.Println(now) // 2026-07-27 15:04:05.123456789 +0800 CST

time.Now() 返回当前本地时间。

创建指定时间

t1 := time.Date(2026, 7, 27, 15, 0, 0, 0, time.Local)
t2 := time.Date(2026, time.July, 27, 12, 0, 0, 0, time.UTC)

注意月份用 time.July 这种常量,不是数字 7,虽然效果一样但更清晰。

time.Duration

Duration 表示时间间隔,单位是纳秒:

var d time.Duration = 5 * time.Second
fmt.Println(d) // 5s

d2 := 500 * time.Millisecond
d3 := 2 * time.Hour

常用单位常量:

time.Nanosecond
time.Microsecond
time.Millisecond
time.Second
time.Minute
time.Hour
Tip

别用 time.Sleep(5) 这种写法,5 是纳秒等于没睡。一定要带单位:time.Sleep(5 * time.Second)

时间运算

start := time.Now()

// 加减
later := start.Add(2 * time.Hour)
before := start.Add(-30 * time.Minute)

// 两个时间差
diff := later.Sub(start)
fmt.Println(diff) // 2h0m0s

// 比较
start.Before(later)   // true
start.After(later)    // false
start.Equal(start)    // true

格式化时间(重点)

Go 的时间格式化很特别,不用 YYYY-MM-DD,而是用一个参考时间当模板:

2006-01-02 15:04:05

这个时间是 1月2日下午3点4分5秒 2006年,对应 1 2 3 4 5 6。记住「1-2-3-4-5-6」就行。

now := time.Now()

// 格式化
s := now.Format("2006-01-02 15:04:05")
fmt.Println(s) // 2026-07-27 15:04:05

s2 := now.Format("2006/01/02")
fmt.Println(s2) // 2026/07/27

s3 := now.Format("15:04")
fmt.Println(s3) // 15:04
Warning

格式化字符串里写错数字就出不来正确结果。2006 是年、01 是月、02 是日、15 是时(24小时制)、04 是分、05 是秒。写 2024-01-02 这种常见错误是无效的。

常用模板速查:

模板效果
2006-01-022026-07-27
15:04:0515:04:05
2006-01-02 15:04:052026-07-27 15:04:05
2006010220260727
2006-01-02T15:04:05Z07:00RFC3339 格式
Jan 2, 2006Jul 27, 2026
2006-01-02 03:04:05 PM2026-07-27 03:04:05 PM(12小时制)

解析时间字符串

time.Parse 把字符串解析成 Time

t, err := time.Parse("2006-01-02", "2026-07-27")
if err != nil {
	fmt.Println("解析失败:", err)
}
fmt.Println(t) // 2026-07-27 00:00:00 +0000 UTC

Parse 按时区 UTC 解析。想按本地时区用 ParseInLocation

loc, _ := time.LoadLocation("Asia/Shanghai")
t, _ := time.ParseInLocation("2006-01-02 15:04:05", "2026-07-27 15:00:00", loc)

时间戳

now := time.Now()

sec := now.Unix()          // 秒级时间戳
nano := now.UnixNano()     // 纳秒级时间戳
milli := now.UnixMilli()   // 毫秒级时间戳(Go 1.17+)

// 从时间戳还原
t := time.Unix(sec, 0)

Timer 定时器

Timer 到时间触发一次:

timer := time.NewTimer(2 * time.Second)

fmt.Println("等待中...")
<-timer.C // 阻塞 2 秒
fmt.Println("时间到")

// 提前停止
timer.Stop()

time.After 是简化版,直接返回一个只读 channel:

<-time.After(2 * time.Second) // 等 2 秒

Ticker 周期触发

Ticker 按固定间隔重复触发:

ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()

for i := 0; i < 5; i++ {
	<-ticker.C
	fmt.Println("tick", i)
}

配合 select 可以实现定时任务和超时:

ticker := time.NewTicker(500 * time.Millisecond)
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()

for {
	select {
	case <-ticker.C:
		fmt.Println("干活")
	case <-ctx.Done():
		fmt.Println("结束")
		return
	}
}

时区处理

// 获取时区
loc, err := time.LoadLocation("Asia/Shanghai")
loc2, err := time.LoadLocation("America/New_York")

// 在指定时区显示时间
now := time.Now()
shanghaiTime := now.In(loc)
nyTime := now.In(loc2)

fmt.Println(shanghaiTime.Format("2006-01-02 15:04:05"))
fmt.Println(nyTime.Format("2006-01-02 15:04:05"))
Note

服务端处理时间建议内部统一用 UTC,只在展示时转成用户时区。数据库存 UTC,前端按需转换。这样能避免很多时区混乱问题。

小结

  • time.Now() 取当前时间,time.Date() 创建指定时间
  • Duration 表示间隔,必须带单位(5 * time.Second
  • 格式化用参考时间 2006-01-02 15:04:05 当模板
  • time.Parse 解析字符串,注意时区
  • Timer 触发一次,Ticker 周期触发
  • 内部用 UTC,展示时转时区

下一节讲 encoding/json。