时间处理
time 包核心
获取时间
now := time.Now() // 当前本地时间
utc := time.Now().UTC() // UTC 时间
// 构造指定时间
t := time.Date(2026, 8, 4, 20, 34, 0, 0, time.Local)
// 年 月 日 时 分 秒 纳秒 时区
// Unix 时间戳
now.Unix() // 秒(int64)
now.UnixMilli() // 毫秒(Go 1.17+)
now.UnixMicro() // 微秒(Go 1.17+)
now.UnixNano() // 纳秒
// 从时间戳创建
t := time.Unix(1691157600, 0) // 秒
t := time.UnixMilli(1691157600000) // 毫秒
时间格式化
// Go 的格式化用「参考时间」:2006-01-02 15:04:05
// 这个时间是 1月2日 3点4分5秒 2006年 → 1 2 3 4 5 6
t := time.Now()
// 格式化
t.Format("2006-01-02 15:04:05") // "2026-08-04 20:34:00"
t.Format("2006-01-02") // "2026-08-04"
t.Format("15:04:05") // "20:34:00"
t.Format("2006/01/02 15:04") // "2026/08/04 20:34"
t.Format("2006-01-02T15:04:05Z07:00") // RFC3339 格式
// 预定义格式
t.Format(time.RFC3339) // "2026-08-04T20:34:00+08:00"
t.Format(time.RFC822) // "04 Aug 26 20:34 CST"
t.Format(time.RFC1123) // "Mon, 04 Aug 2026 20:34:00 CST"
t.Format(time.Kitchen) // "8:34PM"
t.Format(time.Stamp) // "Aug 4 20:34:00"
// 自定义格式参考表
// 2006 → 年 01 → 月 02 → 日
// 15 → 时(24) 03 → 时(12) 04 → 分 05 → 秒
// .000 → 毫秒 .000000 → 微秒 .000000000 → 纳秒
// MST → 时区名 -0700 → 时区偏移 Z0700 → UTC时区
// PM → 上午/下午
时间解析
// 解析
t, err := time.Parse("2006-01-02", "2026-08-04")
t, err := time.Parse("2006-01-02 15:04:05", "2026-08-04 20:34:00")
t, err := time.Parse(time.RFC3339, "2026-08-04T20:34:00+08:00")
// 带时区解析
loc, _ := time.LoadLocation("Asia/Shanghai")
t, err := time.ParseInLocation("2006-01-02 15:04:05", "2026-08-04 20:34:00", loc)
// 解析 Unix 时间戳
t := time.Unix(1691157600, 0)
格式化参考对照表
| 格式符 | 含义 | 示例 |
|---|
2006 | 4位年 | 2026 |
06 | 2位年 | 26 |
01 | 2位月 | 08 |
Jan | 月缩写 | Aug |
January | 月全称 | August |
02 | 2位日 | 04 |
Monday | 星期全称 | Monday |
Mon | 星期缩写 | Mon |
15 | 24小时制 | 20 |
03 | 12小时制 | 08 |
04 | 分钟 | 34 |
05 | 秒 | 00 |
.000 | 毫秒 | .000 |
PM | 上午/下午 | PM |
MST | 时区名 | CST |
-0700 | 时区偏移 | +0800 |
Z0700 | UTC 时区 | Z |
记忆技巧:1月2日下午3点4分5秒 2006年 → 01/02 03:04:05PM '06 → 数字递增 1 2 3 4 5 6
时间计算
t1 := time.Date(2026, 8, 4, 10, 0, 0, 0, time.Local)
t2 := time.Date(2026, 8, 6, 14, 0, 0, 0, time.Local)
// 时间差
dur := t2.Sub(t1) // Duration: 52h0m0s
dur.Hours() // 52.0
dur.Minutes() // 3120.0
dur.Seconds() // 187200
// 时间加减
t3 := t1.Add(24 * time.Hour) // 加 1 天
t4 := t1.Add(-2 * time.Hour) // 减 2 小时
t5 := t1.AddDate(0, 1, 0) // 加 1 个月(年 月 日)
// 比较
t1.Before(t2) // true
t1.After(t2) // false
t1.Equal(t2) // false
// 判断是否为零值
var t time.Time
t.IsZero() // true
// 截断到指定精度
t.Truncate(time.Hour) // 截断到整点
t.Truncate(24 * time.Hour) // 截断到整天(注意时区)
Duration
// Duration 是 int64 的纳秒数
var d time.Duration = 5 * time.Second
// 常量
time.Nanosecond // 1ns
time.Microsecond // 1μs
time.Millisecond // 1ms
time.Second // 1s
time.Minute // 1m
time.Hour // 1h
// 运算
d := 2*time.Hour + 30*time.Minute // 2h30m
d.Hours() // 2.5
d.Minutes() // 150
// Duration 格式化
d.String() // "2h30m0s"
d.Round(time.Minute) // 四舍五入到分钟
时区处理
// 获取时区
loc, _ := time.LoadLocation("Asia/Shanghai")
loc, _ := time.LoadLocation("America/New_York")
loc, _ := time.LoadLocation("UTC")
// 固定偏移时区
loc := time.FixedZone("CST", 8*3600) // UTC+8
// 转换时区
t := time.Now()
shanghaiTime := t.In(loc) // 转换为上海时间
// 获取时区信息
zone, offset := t.Zone()
// zone = "CST", offset = 28800(秒)
定时器
// Ticker:周期触发
ticker := time.NewTicker(5 * time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
fmt.Println("tick at", time.Now())
case <-ctx.Done():
return
}
}
// Timer:单次触发
timer := time.NewTimer(10 * time.Second)
defer timer.Stop()
select {
case <-timer.C:
fmt.Println("timer fired")
case <-ctx.Done():
return
}
// time.After:简化版(无法取消)
select {
case <-time.After(5 * time.Second):
fmt.Println("timeout")
case result := <-ch:
fmt.Println("got result")
}
// time.Sleep:阻塞
time.Sleep(2 * time.Second)
常见时间操作
// 获取当天开始时间
func StartOfDay(t time.Time) time.Time {
y, m, d := t.Date()
return time.Date(y, m, d, 0, 0, 0, 0, t.Location())
}
// 获取当天结束时间
func EndOfDay(t time.Time) time.Time {
y, m, d := t.Date()
return time.Date(y, m, d, 23, 59, 59, 999999999, t.Location())
}
// 获取本周第一天(周一)
func StartOfWeek(t time.Time) time.Time {
t = StartOfDay(t)
days := int(t.Weekday()) - 1
if days < 0 {
days = 6 // Sunday → 6
}
return t.AddDate(0, 0, -days)
}
// 获取月初
func StartOfMonth(t time.Time) time.Time {
return time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location())
}
// 获取月末
func EndOfMonth(t time.Time) time.Time {
return StartOfMonth(t).AddDate(0, 1, 0).Add(-time.Nanosecond)
}
// 判断闰年
func IsLeapYear(year int) bool {
return year%4 == 0 && (year%100 != 0 || year%400 == 0)
}
time 包常见陷阱
| 陷阱 | 说明 | 解决方案 |
|---|
time.Sleep 无法取消 | 阻塞当前 goroutine | 用 time.NewTimer + select |
time.After 资源泄漏 | 每次 After 创建 Timer,不取消会到时间才回收 | 用 time.NewTimer + Stop() |
| 时区不一致 | 不同服务器时区不同 | 统一用 UTC 存储,显示时转换 |
AddDate 溢出 | time.Date(2026,1,31).AddDate(0,1,0) → 3月3日 | 注意月末日期 |
| 格式化字符串记不住 | 不是 YYYY-MM-DD | 记住 2006-01-02 |