time.Now() 默认返回本地时区时间而非 UTC,易在跨时区场景引发错误;time.Parse 仅支持 Go 特定“魔数”格式;Add/Sub 操作需用 time.Duration;Format 不输出时区需显式指定。

time.Now() 返回的是本地时区时间,不是 UTC
绝大多数情况下你拿到的 time.Now() 是带本地时区偏移的,比如 2026-07-14 14:03:00.123456 +0800 CST。这不是 bug,是设计——Go 默认用 time.Local。但如果你在日志聚合、跨时区服务或数据库写入场景下直接用它,可能出问题。
- 写入 PostgreSQL 的
timestamptz字段时,如果传入本地时间却没显式转 UTC,PostgreSQL 会按客户端时区再转换一次,结果错乱 - 微服务间通过 JSON 传递时间字段,若一方用
time.Now().UTC().Format(...),另一方用time.Now().Format(...),解析后时间差 8 小时 - 定时任务(如每天凌晨 2 点触发)若依赖本地时间,在服务器迁移至不同地区后行为突变
time.Parse 的格式字符串必须是 "2006-01-02 15:04:05"
不是任意占位符都能用,time.Parse 只认 Go 的“魔数”格式:年份固定写 2006,月份固定写 01,小时固定写 15(24 小时制),分钟秒数都带前导零。写成 "YYYY-MM-DD HH:mm:ss" 或 "%Y-%m-%d %H:%M:%S" 会直接 panic,错误信息是 parsing time "...": month out of range。
- 常见错误:从前端传来的 ISO 格式时间字符串如
"2026-07-14T14:03:00+08:00",直接用time.Parse("2006-01-02 15:04:05", s)会失败,得用time.RFC3339或自定义格式"2006-01-02T15:04:05Z07:00" - 空格和大小写敏感:
"2006-01-02 15:04:05"和"2006-01-02 15:04:05 "(末尾多空格)解析结果不同,后者返回 error - 推荐做法:对已知格式,优先用
time.RFC3339、time.RFC822等内置常量;不确定时,先用strings.TrimSpace()清理输入
Add 和 Sub 操作的对象是 time.Time,不是字符串或 int
time.Add() 和 time.Sub() 只接受 time.Duration 类型参数,不能传整数秒或字符串。误传会导致编译失败或运行时 panic。例如 now.Add(3600) 是错的,now.Add("1h") 也错——Go 不做隐式类型转换。
- 正确写法:
now.Add(1 * time.Hour)、now.Add(30 * time.Minute)、now.Add(-7 * 24 * time.Hour) - Duration 构造要小心:
time.Second * 60是合法的,但time.Second * 60 * 60如果左边是int32可能溢出(虽 Go 通常推导为 int64,但显式写time.Hour更安全) -
Sub返回的是time.Duration,不是time.Time;想算“3 天前”,别写now.Sub(3*24*time.Hour),那是负 Duration,应写now.Add(-3*24*time.Hour)
time.Format 输出不含时区缩写,除非显式加 MST/UTC
time.Format("2006-01-02 15:04:05") 只输出时间部分,不带时区信息。即使原始 time.Time 对象包含 +0800 CST,格式化后也会丢掉。这在调试和审计日志中容易埋坑。
立即学习“go语言免费学习笔记(深入)”;
- 需要时区标识时,必须在格式串里加上:例如
"2006-01-02 15:04:05 MST"或"2006-01-02 15:04:05 -0700" -
MST是占位符,实际输出取决于当前时区名称(CST、PDT、UTC 等),不是固定字符串;而-0700输出固定偏移,更可控 - 日志系统若依赖时间字符串做排序或查询,建议统一用 UTC +
"2006-01-02T15:04:05Z"格式,避免时区歧义
业务逻辑中真正麻烦的从来不是“怎么写”,而是“什么时候该用 UTC、什么时候该用本地时间、谁负责转换、边界在哪”。这些细节不提前对齐,上线后查时区 bug 要花三倍时间。


















