Go 1.17+ 才支持 UnixMilli,低版本会编译失败;它返回自 Unix 纪元起的毫秒数(向下取整),精度介于 Unix(秒)和 UnixNano(纳秒)之间,适用于 Web API 和日志,使用时需明确字段语义并注意时区解析一致性。

Go 1.17+ 才有 UnixMilli,低版本会编译失败
如果你的 Go 版本低于 1.17(比如 1.16 或更早),直接调用 t.UnixMilli() 会导致编译错误:undefined: time.Time.UnixMilli。这不是写法问题,是 API 根本不存在。
检查版本:运行 go version;升级建议:使用 go install golang.org/dl/go1.22.0@latest && go1.22.0 download(按需切换)。
- Go 1.17 引入
UnixMilli,返回int64毫秒数(自 Unix 纪元起) - 它等价于
t.Unix() * 1e3 + int64(t.Nanosecond()/1e6),但更简洁、无溢出风险 - 注意:不是“四舍五入到毫秒”,而是向下取整到最近的毫秒(纳秒部分直接截断)
UnixMilli 和 UnixNano / Unix 的精度差异要分清
三者返回单位不同,混用容易导致时间错乱,尤其在做前后端时间比对或数据库存储时。
-
t.Unix()→ 秒(int64),丢失毫秒以下全部精度 -
t.UnixMilli()→ 毫秒(int64),适合大多数 Web API 和日志打点场景 -
t.UnixNano()→ 纳秒(int64),数值极大(约 10^18),JSON 序列化可能溢出 JavaScriptNumber(最大安全整数 2^53−1)
示例:
t := time.Date(2024, 1, 1, 12, 0, 0, 123456789, time.UTC) fmt.Println(t.Unix()) // 1704110400 fmt.Println(t.UnixMilli()) // 1704110400123 ← 123 毫秒(123456789 ns → 123 ms) fmt.Println(t.UnixNano()) // 1704110400123456789
传给 JSON 或 HTTP API 时,UnixMilli 值需要显式转成 float64 或字符串
Go 的 json.Marshal 默认不会把 int64 自动包装成带单位的结构体;如果你直接把 UnixMilli() 结果塞进 map 或 struct 字段,它就只是个裸数字——前端可能误以为是秒级时间戳。
- 常见错误:前端用
new Date(1704110400123)是对的,但若误写成new Date(1704110400123 * 1000)就偏移 1000 倍 - 推荐做法:字段命名带单位,比如
"timestamp_ms",并在文档/注释里明确说明 - 避免隐式转换:不要依赖
time.Time的 JSON marshaler(它输出 RFC3339 字符串),如需毫秒数,显式赋值
正确示例:
data := map[string]any{
"event": "login",
"timestamp_ms": time.Now().UnixMilli(), // 明确语义
}
b, _ := json.Marshal(data) // → {"event":"login","timestamp_ms":1704110400123}跨时区计算时,UnixMilli 值不变,但要注意 time.Time 的内部表示
UnixMilli() 始终基于 UTC 时间计算,和 time.Time 的 Location 无关。这意味着你调用 t.In(shanghai).UnixMilli() 和 t.In(nyc).UnixMilli() 只要对应同一时刻,结果完全一致。
- 别被
.In(...)迷惑:它只影响格式化输出(如Format)和小时/分钟计算,不改变时间戳本质 - 陷阱:用
time.ParseInLocation解析字符串后忘记确认是否已转为 UTC,再调UnixMilli就可能因时区偏差导致错误毫秒值 - 稳妥做法:解析后统一转 UTC:
t.In(time.UTC).UnixMilli()
例如:
loc, _ := time.LoadLocation("Asia/Shanghai")
t, _ := time.ParseInLocation("2006-01-02", "2024-01-01", loc)
// t 是上海时区的 2024-01-01 00:00:00,对应 UTC 是 2023-12-31 16:00:00
fmt.Println(t.UnixMilli()) // 1704038400000 ← 上海本地时间的毫秒戳(即 UTC 时间戳)
fmt.Println(t.In(time.UTC).UnixMilli()) // 同上,值一样毫秒时间戳本身没有时区,真正容易出错的是解析和显示环节——UnixMilli 很干净,但前后端对“这个数字代表什么”缺乏共识时,问题就藏不住了。


















