Go time.Unix() 参数顺序易错,毫秒时间戳需转换为秒+纳秒或用UnixMilli();time.Parse() 仅支持Go特有Layout格式;Format()时区需显式指定;UnixMilli()并发下不唯一,须结合序号或专用库。

time.Unix() 转时间对象时传错参数顺序
Go 的 time.Unix() 要求第一个参数是秒数,第二个是纳秒数 —— 很多人误把毫秒当秒传进去,结果得到 1970 年的日期。比如 time.Unix(1717027200000, 0) 实际解析的是 1717 年,因为 Go 把它当成了秒。
- 毫秒时间戳要先除以 1000 得秒数,余数转纳秒:
time.Unix(ms/1000, (ms%1000)*1e6) - 用
time.UnixMilli()(Go 1.17+)更安全,直接接收毫秒:time.UnixMilli(1717027200000) - 低于 Go 1.17 的项目别自己手算,用
time.Unix(0, ms*int64(time.Millisecond))更可靠
time.Parse() 格式字符串写成常见日期样式就报错
time.Parse() 不认 "yyyy-MM-dd" 或 "%Y-%m-%d" 这类惯用写法 —— 它只认 Go 自己那套魔性 Layout,本质是用一个固定时间点 "Mon Jan 2 15:04:05 MST 2006" 的格式做模板。写错一位、多空格、少时区都会 panic。
- 想解析
"2024-05-30",Layout 必须是"2006-01-02",不是"YYYY-MM-DD" - 带时区的如
"2024-05-30T14:30:00+08:00",Layout 是"2006-01-02T15:04:05Z07:00"(注意小时是 24 小时制的15,不是03) - 不确定输入格式时,别硬 parse,优先用
time.LoadLocation()配合ParseInLocation()控制时区行为
time.Format() 输出的时区不对,本地时间变 UTC
time.Time 值自带时区信息,但很多人调 Format() 前没检查 t.Location(),结果本该输出北京时间却打出 UTC 时间 —— 因为从 time.Unix() 或 Parse() 解析出来的默认是 UTC,不是本地。
- 确认时区:打印
t.Location().String(),常见值有UTC、Local、Asia/Shanghai - 转本地时间用
t.In(time.Local),但注意time.Local依赖系统时区设置,生产环境建议显式加载:loc, _ := time.LoadLocation("Asia/Shanghai"),再用t.In(loc) - 如果只是想按东八区格式输出且不依赖系统,用
t.In(loc).Format(...),别信t.Format(...)默认就对
time.Now().UnixMilli() 在高并发下被当成“唯一 ID”用出问题
毫秒级时间戳在单机高频请求下极易重复 —— 比如 Web 服务每秒处理上千请求,同一毫秒内多个 goroutine 调 time.Now().UnixMilli() 会拿到相同值,导致 ID 冲突或日志覆盖。
立即学习“go语言免费学习笔记(深入)”;
- 别单独依赖
UnixMilli()做唯一标识,至少拼上随机数或自增序号:fmt.Sprintf("%d-%d", time.Now().UnixMilli(), atomic.AddInt64(&counter, 1)) - 需要强唯一性时,改用
xid或ulid库,它们把时间、机器信息、随机数打包进无符号整数 - 注意
UnixMicro()(Go 1.19+)精度更高,但依然不能解决并发重复问题,只是把冲突窗口缩小到微秒级
Layout 字符串记不住没关系,把 "2006-01-02 15:04:05" 这行贴在编辑器边栏就行;真正容易翻车的是时区隐式转换和并发下的时间戳重复——这两处没打日志很难排查。










