time.Now() 返回带本地时区的 time.Time 值;需 UTC 用 .UTC(),Unix 时间戳用 .Unix() 或 .UnixMilli();格式化须用固定参考时间 "2006-01-02 15:04:05" 并显式添加时区标识;高并发下应避免频繁格式化;测试时应通过可注入函数替代直接调用。

time.Now() 返回的是本地时区的时间,不是 UTC,也不是 Unix 时间戳——这是绝大多数新手第一次用就出错的地方。
如何正确获取当前时间
Go 的 time.Now() 直接返回一个 time.Time 类型值,它内部已包含时区信息(默认是本地时区)。不需要额外调用 time.Local 或手动设置时区来“转换”:
now := time.Now() // 就是本地时间,带时区偏移
如果你需要 UTC 时间,显式调用 time.Now().UTC();如果只需要 Unix 秒数,用 time.Now().Unix();要毫秒级时间戳,用 time.Now().UnixMilli()。
格式化输出时容易忽略时区
用 time.Format() 时,Go 不按常见 YYYY-MM-DD 格式写,而是用「参考时间」"2006-01-02 15:04:05"(这是 Go 的固定魔术字符串,不是占位符):
立即学习“go语言免费学习笔记(深入)”;
-
time.Now().Format("2006-01-02 15:04:05")→ 输出本地时间格式化结果 -
time.Now().UTC().Format("2006-01-02 15:04:05")→ 输出 UTC 时间,但字符串里不带+0000 - 要显示时区偏移,得加
Z或MST:例如"2006-01-02 15:04:05 -0700"
漏掉时区标识,会导致日志或 API 返回时间看起来“对”,实则跨时区解析失败。
time.Now() 在高并发场景下的性能影响
time.Now() 本身开销极小(纳秒级),但频繁调用 + 格式化(尤其是带时区的字符串生成)会成为瓶颈:
- 避免在 hot path 中反复调用
time.Now().Format(...) - 如需大量时间字符串,考虑预定义 layout 常量:
const logLayout = "2006-01-02T15:04:05.000Z0700" - 若只比大小、算差值,直接用
time.Time值比较,别转成字符串再 parse
另外,time.Now() 是系统调用,Linux 下走 clock_gettime(CLOCK_REALTIME, ...),在容器或虚拟化环境中可能受宿主机时钟漂移影响,敏感业务应搭配 NTP 同步检查。
测试中伪造当前时间的常见错误
单元测试里不能直接 mock time.Now(它是函数,不是变量),正确做法是把时间获取逻辑抽象成可注入的函数:
type Clock interface { Now() time.Time }
// 或更轻量:
var nowFunc = func() time.Time { return time.Now() }
// 测试时替换:
nowFunc = func() time.Time { return time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC) }
硬写 time.Now = ... 会编译失败;用 monkey patch 工具(如 gomonkey)虽可行,但增加依赖且不稳定,不推荐用于核心逻辑。
真正麻烦的不是怎么调用 time.Now(),而是后续所有基于它的操作——格式化、存储、序列化、跨服务传递——是否一致地处理了时区和精度。一个 .UTC() 漏写,可能让凌晨三点的订单被当成前一天处理。


















