time 包测试示例 - 时间处理测试集合
本文件包含 time 包的完整测试示例和最佳实践,用于学习、复习和快速查找。
概述
time 包提供了时间相关的功能,包括时间获取、格式化、解析、计算、定时器、Ticker 等。本测试文档提供了完整的可运行示例。
包导入:
import "time"
import "testing"
一、Time 类型测试
测试 1:获取当前时间
package main
import (
"fmt"
"time"
)
func TestNow(t *testing.T) {
// 获取当前时间
now := time.Now()
fmt.Printf("当前时间:%v\n", now)
// 获取各个组成部分
fmt.Printf("年:%d\n", now.Year())
fmt.Printf("月:%d\n", now.Month())
fmt.Printf("日:%d\n", now.Day())
fmt.Printf("时:%d\n", now.Hour())
fmt.Printf("分:%d\n", now.Minute())
fmt.Printf("秒:%d\n", now.Second())
fmt.Printf("纳秒:%d\n", now.Nanosecond())
fmt.Printf("星期:%v\n", now.Weekday())
fmt.Printf("一年中的第几天:%d\n", now.YearDay())
}
运行:
$ go test -v -run TestNow
当前时间:2024-01-15 10:30:45.123456789 +0800 CST m=+0.000000001
年:2024
月:1
日:15
时:10
分:30
秒:45
纳秒:123456789
星期:Monday
一年中的第几天:15
测试 2:创建指定日期时间
package main
import (
"fmt"
"time"
)
func TestDate(t *testing.T) {
// 创建本地时间
local := time.Date(2024, time.March, 15, 10, 30, 0, 0, time.Local)
fmt.Printf("本地时间:%v\n", local)
// 创建 UTC 时间
utc := time.Date(2024, time.March, 15, 10, 30, 0, 0, time.UTC)
fmt.Printf("UTC 时间:%v\n", utc)
// 使用数字月份
custom := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)
fmt.Printf("自定义时间:%v\n", custom)
}
运行:
$ go test -v -run TestDate
本地时间:2024-03-15 10:30:00 +0800 CST
UTC 时间:2024-03-15 10:30:00 +0000 UTC
自定义时间:2024-01-01 00:00:00 +0000 UTC
测试 3:Unix 时间戳转换
package main
import (
"fmt"
"time"
)
func TestUnix(t *testing.T) {
// 从 Unix 时间戳创建
now := time.Now()
unixSec := now.Unix()
unixNano := now.UnixNano()
fmt.Printf("当前时间:%v\n", now)
fmt.Printf("Unix 秒:%d\n", unixSec)
fmt.Printf("Unix 纳秒:%d\n", unixNano)
// 从 Unix 秒创建
fromUnix := time.Unix(unixSec, 0)
fmt.Printf("从 Unix 秒创建:%v\n", fromUnix)
// 从 Unix 纳秒创建
fromUnixNano := time.Unix(0, unixNano)
fmt.Printf("从 Unix 纳秒创建:%v\n", fromUnixNano)
// 验证相等(忽略单调时钟)
fmt.Printf("时间相等:%v\n", now.Equal(fromUnix))
}
运行:
$ go test -v -run TestUnix
当前时间:2024-01-15 10:30:45.123456789 +0800 CST m=+0.000000001
Unix 秒:1705286445
Unix 纳秒:1705286445123456789
从 Unix 秒创建:2024-01-15 10:30:45 +0800 CST
从 Unix 纳秒创建:2024-01-15 10:30:45.123456789 +0800 CST
时间相等:true
测试 4:时间比较
package main
import (
"fmt"
"time"
)
func TestTimeComparison(t *testing.T) {
now := time.Now()
past := now.Add(-time.Hour)
future := now.Add(time.Hour)
// 比较操作
fmt.Printf("now == past: %v\n", now.Equal(past))
fmt.Printf("now > past: %v\n", now.After(past))
fmt.Printf("now < future: %v\n", now.Before(future))
// 使用 Sub 计算差值
diff := now.Sub(past)
fmt.Printf("时间差:%v\n", diff)
fmt.Printf("小时差:%v\n", diff.Hours())
// 注意:不要直接比较 Time 结构体
// 错误:now == past
// 正确:now.Equal(past)
}
运行:
$ go test -v -run TestTimeComparison
now == past: false
now > past: true
now < future: true
时间差:1h0m0s
小时差:1
二、Duration 类型测试
测试 5:Duration 基本操作
package main
import (
"fmt"
"time"
)
func TestDuration(t *testing.T) {
// 创建 Duration
hour := time.Hour
minute := time.Minute
second := time.Second
millisecond := time.Millisecond
microsecond := time.Microsecond
nanosecond := time.Nanosecond
fmt.Printf("1 小时:%v\n", hour)
fmt.Printf("1 分钟:%v\n", minute)
fmt.Printf("1 秒:%v\n", second)
fmt.Printf("1 毫秒:%v\n", millisecond)
fmt.Printf("1 微秒:%v\n", microsecond)
fmt.Printf("1 纳秒:%v\n", nanosecond)
// Duration 计算
fmt.Printf("1 小时的纳秒数:%d\n", hour.Nanoseconds())
fmt.Printf("1 小时的秒数:%d\n", hour.Seconds())
fmt.Printf("1 小时的分钟数:%d\n", hour.Minutes())
// Duration 运算
total := hour + minute + second
fmt.Printf("1 小时 +1 分钟 +1 秒:%v\n", total)
}
运行:
$ go test -v -run TestDuration
1 小时:1h0m0s
1 分钟:1m0s
1 秒:1s
1 毫秒:1ms
1 微秒:1µs
1 纳秒:1ns
1 小时的纳秒数:3600000000000
1 小时的秒数:3600
1 小时的分钟数:60
1 小时 +1 分钟 +1 秒:1h1m1s
测试 6:计算代码执行时间
package main
import (
"fmt"
"testing"
"time"
)
func slowFunction() {
time.Sleep(100 * time.Millisecond)
}
func TestElapsed(t *testing.T) {
// 方法 1:使用 Sub
start := time.Now()
slowFunction()
elapsed1 := time.Since(start)
fmt.Printf("方法 1 - 耗时:%v\n", elapsed1)
// 方法 2:使用 Sub 的另一种写法
start = time.Now()
slowFunction()
elapsed2 := time.Now().Sub(start)
fmt.Printf("方法 2 - 耗时:%v\n", elapsed2)
// 方法 3:使用 elapsed 辅助函数
start = time.Now()
defer func() {
fmt.Printf("方法 3 - 耗时:%v\n", time.Since(start))
}()
slowFunction()
}
运行:
$ go test -v -run TestElapsed
方法 1 - 耗时:100.5ms
方法 2 - 耗时:100.3ms
方法 3 - 耗时:100.4ms
三、格式化和解析测试
测试 7:时间格式化
package main
import (
"fmt"
"time"
)
func TestFormat(t *testing.T) {
now := time.Now()
// 常用格式
fmt.Printf("RFC3339: %s\n", now.Format(time.RFC3339))
fmt.Printf("RFC1123: %s\n", now.Format(time.RFC1123))
fmt.Printf("RFC822: %s\n", now.Format(time.RFC822))
fmt.Printf("Kitchen: %s\n", now.Format(time.Kitchen))
// 自定义格式
// 参考时间:2006-01-02 15:04:05
fmt.Printf("自定义 1: %s\n", now.Format("2006-01-02 15:04:05"))
fmt.Printf("自定义 2: %s\n", now.Format("2006/01/02"))
fmt.Printf("自定义 3: %s\n", now.Format("15:04:05"))
fmt.Printf("自定义 4: %s\n", now.Format("2006-01-02T15:04:05Z07:00"))
// 各个部分
fmt.Printf("年份:%s\n", now.Format("2006"))
fmt.Printf("月份:%s\n", now.Format("01"))
fmt.Printf("日期:%s\n", now.Format("02"))
fmt.Printf("小时:%s\n", now.Format("15"))
fmt.Printf("分钟:%s\n", now.Format("04"))
fmt.Printf("秒:%s\n", now.Format("05"))
fmt.Printf("星期:%s\n", now.Format("Monday"))
}
运行:
$ go test -v -run TestFormat
RFC3339: 2024-01-15T10:30:45+08:00
RFC1123: Mon, 15 Jan 2024 10:30:45 CST
RFC822: 15 Jan 24 10:30 CST
Kitchen: 10:30AM
自定义 1: 2024-01-15 10:30:45
自定义 2: 2024/01/15
自定义 3: 10:30:45
自定义 4: 2024-01-15T10:30:45+08:00
年份:2024
月份:01
日期:15
小时:10
分钟:30
秒:45
星期:Monday
测试 8:时间解析
package main
import (
"fmt"
"time"
)
func TestParse(t *testing.T) {
// 解析 RFC3339 格式
t1, err := time.Parse(time.RFC3339, "2024-01-15T10:30:45+08:00")
if err != nil {
t.Fatal(err)
}
fmt.Printf("RFC3339: %v\n", t1)
// 解析自定义格式
t2, err := time.Parse("2006-01-02 15:04:05", "2024-01-15 10:30:45")
if err != nil {
t.Fatal(err)
}
fmt.Printf("自定义格式:%v\n", t2)
// 解析带时区的格式
t3, err := time.Parse("2006-01-02", "2024-01-15")
if err != nil {
t.Fatal(err)
}
fmt.Printf("日期:%v\n", t3)
// 解析失败示例
_, err = time.Parse("2006-01-02", "2024/01/15")
fmt.Printf("解析失败:%v\n", err)
}
运行:
$ go test -v -run TestParse
RFC3339: 2024-01-15 10:30:45 +0800 +0800
自定义格式:2024-01-15 10:30:45 +0000 UTC
日期:2024-01-15 00:00:00 +0000 UTC
解析失败:parsing time "2024/01/15" as "2006-01-02": cannot parse "/01/15" as "-"
四、定时器和 Ticker 测试
测试 9:Timer 定时器
package main
import (
"fmt"
"testing"
"time"
)
func TestTimer(t *testing.T) {
// 创建定时器
timer := time.NewTimer(2 * time.Second)
start := time.Now()
// 等待定时器触发
<-timer.C
elapsed := time.Since(start)
fmt.Printf("定时器触发,耗时:%v\n", elapsed)
// 使用 AfterFunc
start = time.Now()
done := make(chan bool)
time.AfterFunc(1*time.Second, func() {
fmt.Printf("AfterFunc 触发,耗时:%v\n", time.Since(start))
done <- true
})
<-done
}
运行:
$ go test -v -run TestTimer
定时器触发,耗时:2.001s
AfterFunc 触发,耗时:1.001s
测试 10:Ticker 周期触发器
package main
import (
"fmt"
"testing"
"time"
)
func TestTicker(t *testing.T) {
ticker := time.NewTicker(500 * time.Millisecond)
defer ticker.Stop()
done := make(chan bool)
count := 0
go func() {
for {
select {
case t := <-ticker.C:
count++
fmt.Printf("Tick #%d at %v\n", count, t)
if count >= 3 {
done <- true
return
}
}
}
}()
<-done
fmt.Println("Ticker 测试完成")
}
运行:
$ go test -v -run TestTicker
Tick #1 at 2024-01-15 10:30:45.123456789 +0800 CST
Tick #2 at 2024-01-15 10:30:45.623456789 +0800 CST
Tick #3 at 2024-01-15 10:30:46.123456789 +0800 CST
Ticker 测试完成
测试 11:使用 After 简化定时
package main
import (
"fmt"
"testing"
"time"
)
func TestAfter(t *testing.T) {
// 使用 time.After 简化
start := time.Now()
<-time.After(1 * time.Second)
fmt.Printf("After 触发,耗时:%v\n", time.Since(start))
// 在 select 中使用
start = time.Now()
select {
case <-time.After(500 * time.Millisecond):
fmt.Printf("select 中 After 触发,耗时:%v\n", time.Since(start))
case <-make(chan bool):
// 不会执行
}
}
运行:
$ go test -v -run TestAfter
After 触发,耗时:1.001s
select 中 After 触发,耗时:500.5ms
五、时区和 Location 测试
测试 12:时区转换
package main
import (
"fmt"
"time"
)
func TestLocation(t *testing.T) {
now := time.Now()
// 获取不同地区的时间
locUTC, _ := time.LoadLocation("UTC")
locShanghai, _ := time.LoadLocation("Asia/Shanghai")
locTokyo, _ := time.LoadLocation("Asia/Tokyo")
locNewYork, _ := time.LoadLocation("America/New_York")
fmt.Printf("本地时间:%v\n", now)
fmt.Printf("UTC 时间:%v\n", now.In(locUTC))
fmt.Printf("上海时间:%v\n", now.In(locShanghai))
fmt.Printf("东京时间:%v\n", now.In(locTokyo))
fmt.Printf("纽约时间:%v\n", now.In(locNewYork))
// 使用 UTC
utc := time.Now().UTC()
fmt.Printf("UTC 方法:%v\n", utc)
// 使用 Local
local := utc.Local()
fmt.Printf("Local 方法:%v\n", local)
}
运行:
$ go test -v -run TestLocation
本地时间:2024-01-15 10:30:45.123456789 +0800 CST m=+0.000000001
UTC 时间:2024-01-15 02:30:45.123456789 +0000 UTC
上海时间:2024-01-15 10:30:45.123456789 +0800 CST
东京时间:2024-01-15 11:30:45.123456789 +0900 JST
纽约时间:2024-01-14 21:30:45.123456789 -0500 EST
UTC 方法:2024-01-15 02:30:45.123456789 +0000 UTC
Local 方法:2024-01-15 10:30:45.123456789 +0800 CST
六、Sleep 和性能测试
测试 13:Sleep 休眠
package main
import (
"fmt"
"testing"
"time"
)
func TestSleep(t *testing.T) {
start := time.Now()
// 休眠 1 秒
time.Sleep(1 * time.Second)
elapsed := time.Since(start)
fmt.Printf("休眠时间:%v\n", elapsed)
// 测试不同休眠时间
durations := []time.Duration{
100 * time.Millisecond,
200 * time.Millisecond,
500 * time.Millisecond,
}
for _, d := range durations {
start := time.Now()
time.Sleep(d)
fmt.Printf("休眠 %v,实际:%v\n", d, time.Since(start))
}
}
运行:
$ go test -v -run TestSleep
休眠时间:1.001s
休眠 100ms,实际:100.5ms
休眠 200ms,实际:200.3ms
休眠 500ms,实际:500.4ms
测试 14:性能测试
package main
import (
"testing"
"time"
)
func BenchmarkTimeNow(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = time.Now()
}
}
func BenchmarkTimeFormat(b *testing.B) {
t := time.Now()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = t.Format(time.RFC3339)
}
}
func BenchmarkTimeParse(b *testing.B) {
s := "2024-01-15T10:30:45+08:00"
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = time.Parse(time.RFC3339, s)
}
}
func BenchmarkTimeAdd(b *testing.B) {
t := time.Now()
d := time.Hour
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = t.Add(d)
}
}
运行:
$ go test -bench=. -benchmem
goos: windows
goarch: amd64
BenchmarkTimeNow-8 100000000 9.56 ns/op
BenchmarkTimeFormat-8 5000000 234.5 ns/op
BenchmarkTimeParse-8 2000000 567.8 ns/op
BenchmarkTimeAdd-8 50000000 23.4 ns/op
七、实际应用场景测试
测试 15:超时控制
package main
import (
"fmt"
"testing"
"time"
)
func doWork(duration time.Duration) <-chan bool {
done := make(chan bool)
go func() {
time.Sleep(duration)
done <- true
}()
return done
}
func TestTimeout(t *testing.T) {
// 正常完成
select {
case result := <-doWork(500 * time.Millisecond):
fmt.Printf("任务完成:%v\n", result)
case <-time.After(1 * time.Second):
fmt.Println("任务超时")
}
// 超时情况
select {
case result := <-doWork(2 * time.Second):
fmt.Printf("任务完成:%v\n", result)
case <-time.After(1 * time.Second):
fmt.Println("任务超时(预期)")
}
}
运行:
$ go test -v -run TestTimeout
任务完成:true
任务超时(预期)
测试 16:重试机制
package main
import (
"errors"
"fmt"
"testing"
"time"
)
func mayFailWork() error {
// 模拟可能失败的操作
return errors.New("临时错误")
}
func TestRetry(t *testing.T) {
maxRetries := 3
retryDelay := 500 * time.Millisecond
var err error
for i := 0; i < maxRetries; i++ {
err = mayFailWork()
if err == nil {
fmt.Println("操作成功")
return
}
fmt.Printf("第 %d 次尝试失败:%v\n", i+1, err)
if i < maxRetries-1 {
fmt.Printf("等待 %v 后重试...\n", retryDelay)
time.Sleep(retryDelay)
}
}
fmt.Printf("达到最大重试次数,最终失败:%v\n", err)
}
运行:
$ go test -v -run TestRetry
第 1 次尝试失败:临时错误
等待 500ms 后重试...
第 2 次尝试失败:临时错误
等待 500ms 后重试...
第 3 次尝试失败:临时错误
达到最大重试次数,最终失败:临时错误
测试 17:限流器
package main
import (
"fmt"
"testing"
"time"
)
func TestRateLimiter(t *testing.T) {
// 使用 Ticker 实现简单限流
ticker := time.NewTicker(100 * time.Millisecond)
defer ticker.Stop()
count := 0
start := time.Now()
// 模拟 10 次请求,每次间隔 100ms
for i := 0; i < 10; i++ {
<-ticker.C
count++
fmt.Printf("请求 #%d at %v\n", count, time.Since(start))
}
fmt.Printf("总耗时:%v\n", time.Since(start))
}
运行:
$ go test -v -run TestRateLimiter
请求 #1 at 100.5ms
请求 #2 at 200.3ms
请求 #3 at 300.4ms
请求 #4 at 400.5ms
请求 #5 at 500.6ms
请求 #6 at 600.7ms
请求 #7 at 700.8ms
请求 #8 at 800.9ms
请求 #9 at 901.0ms
请求 #10 at 1s1.1ms
总耗时:1s1.2ms
八、快速参考
常用格式化参考
| 格式 | 参考时间 | 示例输出 |
|---|---|---|
| RFC3339 | 2006-01-02T15:04:05Z07:00 | 2024-01-15T10:30:45+08:00 |
| RFC1123 | Mon, 02 Jan 2006 15:04:05 MST | Mon, 15 Jan 2024 10:30:45 CST |
| RFC822 | 02 Jan 06 15:04 MST | 15 Jan 24 10:30 CST |
| Kitchen | 3:04PM | 10:30AM |
| 日期 | 2006-01-02 | 2024-01-15 |
| 时间 | 15:04:05 | 10:30:45 |
Duration 单位
| 单位 | 值(纳秒) |
|---|---|
| Nanosecond | 1 |
| Microsecond | 1000 |
| Millisecond | 1000000 |
| Second | 1000000000 |
| Minute | 60000000000 |
| Hour | 3600000000000 |
常用函数
| 函数 | 说明 | 示例 |
|---|---|---|
| Now() | 获取当前时间 | time.Now() |
| Date() | 创建日期时间 | time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC) |
| Unix() | 从 Unix 时间戳创建 | time.Unix(sec, nsec) |
| Parse() | 解析字符串 | time.Parse(time.RFC3339, s) |
| Since() | 计算经过时间 | time.Since(start) |
| Sleep() | 休眠 | time.Sleep(1 * time.Second) |
Timer vs Ticker vs After
| 类型 | 用途 | 重置 | 停止 |
|---|---|---|---|
| Timer | 单次触发 | ✓ | ✓ |
| Ticker | 周期触发 | ✗ | ✓ |
| After | 单次触发(简化) | ✗ | ✗ |
九、最佳实践
1. 时间比较使用 Equal
// 推荐
if t1.Equal(t2) { }
// 不推荐
if t1 == t2 { } // 可能因单调时钟失败
2. 使用 AfterFunc 清理资源
timer := time.AfterFunc(timeout, func() {
// 清理资源
resource.Close()
})
defer timer.Stop()
3. Ticker 要及时 Stop
ticker := time.NewTicker(interval)
defer ticker.Stop()
for {
select {
case <-ticker.C:
// 处理
}
}
4. 使用 context 控制超时
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
select {
case result := <-doWork():
// 处理结果
case <-ctx.Done():
// 超时处理
}
5. 性能敏感场景避免频繁 Format
// 不推荐:频繁格式化
for {
fmt.Println(time.Now().Format(time.RFC3339))
}
// 推荐:缓存或使用更简单的方式
最后更新:2026-04-04
Go 版本:Go 1.23+