文章

时间处理

时间处理

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)

格式化参考对照表

格式符含义示例
20064位年2026
062位年26
012位月08
Jan月缩写Aug
January月全称August
022位日04
Monday星期全称Monday
Mon星期缩写Mon
1524小时制20
0312小时制08
04分钟34
0500
.000毫秒.000
PM上午/下午PM
MST时区名CST
-0700时区偏移+0800
Z0700UTC 时区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 无法取消阻塞当前 goroutinetime.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