go
// Time - 表示一个时间点
var t time.Time = time.Now()
// Duration - 表示时间间隔(纳秒精度)
var d time.Duration = 5 * time.Second
// Timer - 一次性定时器
var timer *time.Timer = time.NewTimer(5 * time.Second)
// Ticker - 周期性触发器
var ticker *time.Ticker = time.NewTicker(1 * time.Second)
plain text
Time (时间点)
├── Now() - 获取当前时间
├── Add(Duration) - 加上时间间隔
└── Sub(Time) - 两个时间点相减 → Duration
Duration (时间间隔)
├── Second, Minute, Hour - 常量
└── 用于定时器和时间计算
Timer (一次性)
└── 在指定 Duration 后触发一次
Ticker (周期性)
└── 每隔指定 Duration 触发一次
go
// 获取当前时间(本地时区)
now := time.Now()
fmt.Println(now) // 2025-11-24 10:30:45.123456 +0800 CST
// 获取 UTC 时间
utc := time.Now().UTC()
// 获取 Unix 时间戳
timestamp := time.Now().Unix() // 秒级
timestampMilli := time.Now().UnixMilli() // 毫秒级
timestampNano := time.Now().UnixNano() // 纳秒级
// 从时间戳创建 Time
t := time.Unix(1700000000, 0) // 秒级时间戳
t := time.UnixMilli(1700000000000) // 毫秒级时间戳
go
now := time.Now()
// 加上时间间隔
future := now.Add(2 * time.Hour) // 2小时后
past := now.Add(-30 * time.Minute) // 30分钟前
// 添加日期(年月日)
nextYear := now.AddDate(1, 0, 0) // 1年后
nextMonth := now.AddDate(0, 1, 0) // 1个月后
tomorrow := now.AddDate(0, 0, 1) // 明天
// 两个时间点相减
start := time.Now()
// ... 执行某些操作
end := time.Now()
elapsed := end.Sub(start) // 返回 Duration
fmt.Printf("耗时: %v\n", elapsed)
go
t1 := time.Now()
time.Sleep(100 * time.Millisecond)
t2 := time.Now()
// 比较大小
t1.Before(t2) // true - t1 在 t2 之前
t1.After(t2) // false - t1 在 t2 之后
t1.Equal(t2) // false - 完全相等(考虑时区)
// 判断是否为零值
var t time.Time
t.IsZero() // true
go
now := time.Now()
// 获取各个部分
year := now.Year() // 2025
month := now.Month() // November (类型是 time.Month)
day := now.Day() // 24
hour := now.Hour() // 10
minute := now.Minute() // 30
second := now.Second() // 45
weekday := now.Weekday() // Monday (类型是 time.Weekday)
// 获取年月日
y, m, d := now.Date()
// 获取时分秒
h, min, s := now.Clock()
// 年中的第几天
yearDay := now.YearDay() // 328
go
// time 包预定义的常量
time.Nanosecond // 1 纳秒
time.Microsecond // 1000 纳秒
time.Millisecond // 1000000 纳秒
time.Second // 1000000000 纳秒
time.Minute // 60 秒
time.Hour // 60 分钟
// 使用示例
d := 5 * time.Second // 5秒
d := 100 * time.Millisecond // 100毫秒
d := 2*time.Hour + 30*time.Minute // 2小时30分钟
go
d := 90 * time.Second
// 转换为不同单位
d.Seconds() // 90.0 (float64)
d.Milliseconds() // 90000 (int64)
d.Microseconds() // 90000000 (int64)
d.Nanoseconds() // 90000000000 (int64)
// Duration 运算
d1 := 1 * time.Hour
d2 := 30 * time.Minute
sum := d1 + d2 // 1小时30分钟
diff := d1 - d2 // 30分钟
doubled := d1 * 2 // 2小时
half := d1 / 2 // 30分钟
go
// 解析字符串为 Duration
d, err := time.ParseDuration("1h30m")
// 支持的单位: ns, us(μs), ms, s, m, h
// 常见格式
time.ParseDuration("300ms") // 300毫秒
time.ParseDuration("1.5h") // 1.5小时
time.ParseDuration("2h45m") // 2小时45分钟
time.ParseDuration("1h30m20s") // 1小时30分20秒
// Duration 转字符串
d := 90 * time.Second
s := d.String() // "1m30s"
go
// 创建一次性定时器
timer := time.NewTimer(2 * time.Second)
// 等待定时器触发
<-timer.C // 阻塞,直到 2 秒后
fmt.Println("Timer fired!")
// 简化写法(不需要手动管理 Timer)
<-time.After(2 * time.Second)
fmt.Println("2 seconds passed")
go
timer := time.NewTimer(5 * time.Second)
// 启动 goroutine 等待
go func() {
<-timer.C
fmt.Println("Timer fired!")
}()
// 2秒后取消定时器
time.Sleep(2 * time.Second)
if timer.Stop() {
fmt.Println("Timer stopped before firing")
} else {
fmt.Println("Timer already fired")
}
go
timer := time.NewTimer(1 * time.Second)
// 首次触发
<-timer.C
fmt.Println("First fire")
// 重置定时器为 2 秒
timer.Reset(2 * time.Second)
// 再次触发
<-timer.C
fmt.Println("Second fire")
go
// ❌ 错误用法
timer := time.NewTimer(1 * time.Second)
timer.Reset(2 * time.Second) // 可能有问题
// ✅ 正确用法
timer := time.NewTimer(1 * time.Second)
if !timer.Stop() {
<-timer.C // 先排空 channel
}
timer.Reset(2 * time.Second)
go
func doWithTimeout(timeout time.Duration) error {
timer := time.NewTimer(timeout)
defer timer.Stop()
resultCh := make(chan string)
go func() {
// 执行耗时操作
time.Sleep(3 * time.Second)
resultCh <- "done"
}()
select {
case result := <-resultCh:
fmt.Println("Success:", result)
return nil
case <-timer.C:
return fmt.Errorf("timeout after %v", timeout)
}
}
go
func delayedAction(delay time.Duration, action func()) {
timer := time.AfterFunc(delay, action)
// 可以取消
// timer.Stop()
}
// 使用
delayedAction(5*time.Second, func() {
fmt.Println("5 seconds later")
})
go
// 创建每秒触发一次的 Ticker
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
// 方式 1:循环接收
for i := 0; i < 5; i++ {
t := <-ticker.C
fmt.Println("Tick at", t)
}
// 方式 2:用 range
ticker2 := time.NewTicker(500 * time.Millisecond)
defer ticker2.Stop()
for t := range ticker2.C {
fmt.Println("Tick at", t)
// 需要手动 break 退出
}
go
ticker := time.NewTicker(1 * time.Second)
go func() {
for range ticker.C {
fmt.Println("Tick")
}
}()
// 10 秒后停止
time.Sleep(10 * time.Second)
ticker.Stop()
go
// ❌ 错误:忘记 Stop,导致 goroutine 泄漏
func bad() {
ticker := time.NewTicker(1 * time.Second)
for range ticker.C {
// ...
break // 退出循环,但 ticker 没停止
}
// ticker 仍在运行,永久泄漏
}
// ✅ 正确
func good() {
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop() // 确保停止
for range ticker.C {
// ...
break
}
}
go
func heartbeat(interval time.Duration, stopCh <-chan struct{}) {
ticker := time.NewTicker(interval)
defer ticker.Stop()
for {
select {
case <-ticker.C:
fmt.Println("Heartbeat:", time.Now())
// 发送心跳包
case <-stopCh:
fmt.Println("Heartbeat stopped")
return
}
}
}
// 使用
stopCh := make(chan struct{})
go heartbeat(5*time.Second, stopCh)
// 30秒后停止
time.Sleep(30 * time.Second)
close(stopCh)
go
func periodicTask() {
ticker := time.NewTicker(1 * time.Minute)
defer ticker.Stop()
for range ticker.C {
// 每分钟执行一次
cleanupOldFiles()
collectMetrics()
}
}
go
type RateLimiter struct {
ticker *time.Ticker
}
func NewRateLimiter(requestsPerSecond int) *RateLimiter {
interval := time.Second / time.Duration(requestsPerSecond)
return &RateLimiter{
ticker: time.NewTicker(interval),
}
}
func (rl *RateLimiter) Wait() {
<-rl.ticker.C
}
func (rl *RateLimiter) Stop() {
rl.ticker.Stop()
}
// 使用:限制为每秒 10 个请求
limiter := NewRateLimiter(10)
defer limiter.Stop()
for i := 0; i < 100; i++ {
limiter.Wait() // 控制速率
makeRequest(i)
}
go
now := time.Now()
// 常用格式
now.Format("2006-01-02") // 2025-11-24
now.Format("2006-01-02 15:04:05") // 2025-11-24 10:30:45
now.Format("2006/01/02 15:04:05") // 2025/11/24 10:30:45
now.Format("15:04:05") // 10:30:45
now.Format("3:04 PM") // 10:30 AM
now.Format("Jan 2, 2006") // Nov 24, 2025
now.Format("Monday, 02-Jan-06") // Monday, 24-Nov-25
// 预定义格式常量
now.Format(time.RFC3339) // 2025-11-24T10:30:45+08:00
now.Format(time.RFC822) // 24 Nov 25 10:30 CST
now.Format(time.Kitchen) // 10:30AM
now.Format(time.Stamp) // Nov 24 10:30:45
now.Format(time.DateTime) // 2025-11-24 10:30:45
now.Format(time.DateOnly) // 2025-11-24
now.Format(time.TimeOnly) // 10:30:45
plain text
Mon Jan 2 15:04:05 MST 2006
→ 1 2 3 4 5 6 7
记忆法:1234567
go
// Parse:使用 UTC 时区
t, err := time.Parse("2006-01-02", "2025-11-24")
// ParseInLocation:指定时区
loc, _ := time.LoadLocation("Asia/Shanghai")
t, err := time.ParseInLocation("2006-01-02 15:04:05",
"2025-11-24 10:30:45", loc)
// 常见格式解析
time.Parse(time.RFC3339, "2025-11-24T10:30:45+08:00")
time.Parse("2006-01-02", "2025-11-24")
time.Parse("01/02/2006", "11/24/2025")
go
// 方式 1:手动计算
start := time.Now()
// ... 执行代码
elapsed := time.Since(start)
fmt.Printf("耗时: %v\n", elapsed)
// 方式 2:使用 defer
func timeTrack(start time.Time, name string) {
elapsed := time.Since(start)
fmt.Printf("%s 耗时: %v\n", name, elapsed)
}
func slowFunction() {
defer timeTrack(time.Now(), "slowFunction")
// ... 函数逻辑
time.Sleep(2 * time.Second)
}
go
func fetchWithTimeout(url string, timeout time.Duration) (string, error) {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
resultCh := make(chan string, 1)
errCh := make(chan error, 1)
go func() {
// 模拟 HTTP 请求
time.Sleep(2 * time.Second)
resultCh <- "response data"
}()
select {
case result := <-resultCh:
return result, nil
case err := <-errCh:
return "", err
case <-ctx.Done():
return "", ctx.Err() // context.DeadlineExceeded
}
}
go
func retryWithBackoff(maxRetries int, operation func() error) error {
backoff := 1 * time.Second
for i := 0; i < maxRetries; i++ {
err := operation()
if err == nil {
return nil
}
if i < maxRetries-1 {
fmt.Printf("Retry %d failed, waiting %v\n", i+1, backoff)
time.Sleep(backoff)
backoff *= 2 // 指数退避
}
}
return fmt.Errorf("failed after %d retries", maxRetries)
}
go
func scheduleDaily(hour, minute int, task func()) {
ticker := time.NewTicker(1 * time.Minute)
defer ticker.Stop()
for range ticker.C {
now := time.Now()
if now.Hour() == hour && now.Minute() == minute {
go task() // 在 goroutine 中执行,避免阻塞
}
}
}
// 每天凌晨 2 点执行备份
go scheduleDaily(2, 0, func() {
fmt.Println("Running daily backup...")
// 备份逻辑
})
go
// ❌ 错误:在循环中使用 time.After
for {
select {
case <-time.After(1 * time.Second): // 每次循环创建新 Timer
// 旧的 Timer 无法被GC,造成内存泄漏
process()
}
}
// ✅ 正确:使用 Ticker
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
for range ticker.C {
process()
}
go
// ❌ 错误:Timer/Ticker 没有停止
func bad() {
timer := time.NewTimer(1 * time.Hour)
// ... 使用 timer
return // timer 还在运行,资源泄漏
}
// ✅ 正确:使用 defer
func good() {
timer := time.NewTimer(1 * time.Hour)
defer timer.Stop()
// ... 使用 timer
}
go
// ❌ 错误:直接 Reset 可能 channel 中还有数据
timer := time.NewTimer(1 * time.Second)
// ... timer 触发了
timer.Reset(2 * time.Second) // 可能无效
// ✅ 正确:Reset 前先排空
timer := time.NewTimer(1 * time.Second)
if !timer.Stop() {
<-timer.C // 排空 channel
}
timer.Reset(2 * time.Second)
go
// ❌ 错误:忽略时区
t, _ := time.Parse("2006-01-02 15:04:05", "2025-11-24 10:30:45")
// t 是 UTC 时区!
// ✅ 正确:指定时区
loc, _ := time.LoadLocation("Asia/Shanghai")
t, _ := time.ParseInLocation("2006-01-02 15:04:05",
"2025-11-24 10:30:45", loc)
go
timer := time.NewTimer(1 * time.Second)
// ❌ 错误:多次读取
<-timer.C // 第一次读取,OK
<-timer.C // 永远阻塞!因为 channel 已经空了
// ✅ 正确:Timer 是一次性的,需要 Reset
timer := time.NewTimer(1 * time.Second)
<-timer.C
timer.Reset(1 * time.Second)
<-timer.C