time.Now()获取当前系统时间并返回time.Time类型值,需导入"time"包;UTC时间用.UTC()转换;格式化必须用"2006-01-02 15:04:05"模板;测试时应通过函数变量mock时间。
用 time.Now() 获取当前时间
go 语言里没有“定义当前时间”的概念,只有“获取当前系统时间”,核心就是调用 time.now()。它返回一个 time.time 类型值,包含纳秒精度的本地时间(基于系统时钟和本地时区)。
常见错误是试图用字符串或整数“定义”时间,比如写 now := "2024-05-20" —— 这只是字符串,不是可参与时间计算的 time.Time。
- 直接赋值:
now := time.Now() - 注意导入:
import "time"不可省略 -
time.Now()每次调用都返回新值,不是单例或缓存
需要 UTC 时间?加 .UTC()
默认 time.Now() 返回的是本地时区时间(由系统 TZ 环境变量或运行时决定)。很多服务(日志、API、数据库写入)要求统一用 UTC,否则跨时区部署会出问题。
转换很简单:
nowUTC := time.Now().UTC()
这个操作不改变时间点本身,只切换时区表示。内部时间戳(Unix 纳秒)完全一致。
立即学习“go语言免费学习笔记(深入)”;
- 别用
time.Now().In(time.UTC)—— 效果一样但多一次查找,.UTC()更直白高效 - 如果后续要格式化输出,时区已绑定在
Time值里,Format()会自动按该时区渲染
格式化输出时小心 Format() 的布局字符串
Go 的时间格式化不用 "YYYY-MM-DD" 这类惯用占位符,而是用一个具体的时间值 "2006-01-02 15:04:05" 作为模板 —— 因为 Go 的设计者选了美国中部标准时间(CST)的某个真实时刻做参考。
常见误写:
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
-
time.Now().Format("Y-m-d H:i:s")→ panic:未知动词Y -
time.Now().Format("2024-01-01 12:00:00")→ 输出字面量,不是当前时间
正确写法:
time.Now().Format("2006-01-02 15:04:05") // "2024-05-20 14:32:18"
time.Now().Format("2006-01-02") // "2024-05-20"
记住:年份必须是 2006,月份必须是 01,小时必须是 15(24 小时制),这是硬编码规则,没得商量。
测试中如何“固定”当前时间?
硬依赖 time.Now() 会让单元测试不可靠 —— 时间总在变。实际项目里应该把时间获取抽象成接口或函数变量。
最轻量做法:
var nowFunc = time.Now
func doSomething() {
t := nowFunc() // 而不是直接写 time.Now()
// ...
}
测试时替换:
func TestDoSomething(t *testing.T) {
saved := nowFunc
defer func() { nowFunc = saved }()
nowFunc = func() time.Time {
return time.Date(2024, 5, 20, 12, 0, 0, 0, time.UTC)
}
// run test...
}
真正复杂的系统会用 clock.Clock(如 github.com/andres-erbsen/clock)这类包,但对多数场景,函数变量已足够。
别忘了:生产环境永远用真实 time.Now(),测试才替换 —— 这个边界容易模糊,尤其在集成测试里混用 mock 时间和真实时间,会导致时间跳变类 bug 难以复现。

















