直接在Gin模板中调用.Format方法仅适用于time.Time类型字段;若为int64时间戳或字符串,必须注册支持类型判断、零值防护和时区处理的自定义模板函数。

直接在 Gin 的 HTML 模板里调用 .Format 方法最简单,但前提是传入字段类型是 time.Time;如果后端传的是 int64 时间戳或字符串,必须注册自定义模板函数,否则会 panic 或渲染失败。
模板中直接调用 .Format 只适用于 time.Time 字段
Go 的 html/template 允许对 time.Time 类型字段直接调用其 Format 方法,无需额外注册函数。前提是结构体字段类型确实是 time.Time,且模板中写法正确:
-
{{ .CreatedAt.Format "2006-01-02 15:04:05" }}—— ✅ 有效 -
{{ .CreatedAt | formatTime }}—— ❌ 若未注册formatTime函数,报错undefined function "formatTime" -
{{ .CreatedAtStr.Format "..." }}—— ❌ 若CreatedAtStr是string类型,会 panic:can't call method Format on string
常见错误是数据库字段映射为 string 或 int64,却误以为能链式调用 Format。
传 int64 时间戳时必须注册自定义模板函数
后端习惯用 Unix 时间戳(int64)存创建时间,Gin 模板无法自动识别为时间,需自己处理转换逻辑。注册函数要防 panic,支持零值和多种输入:
- 函数签名必须接收
interface{},内部用type switch判断类型 - 对
int64:区分秒级(< 1e12)和毫秒级(> 1e12),避免time.Unix(0, 0)错误输出 “1970-01-01” - 对空值(
nil、0、"0")统一返回"N/A"或空字符串,不中断渲染 - 注册时机必须在
template.ParseGlob之前,且通过r.SetHTMLTemplate(tmpl)绑定到 Gin 引擎
示例函数片段:
func formatTime(v interface{}) string {
switch x := v.(type) {
case time.Time:
return x.Format("2006-01-02 15:04:05")
case int64:
if x == 0 {
return "N/A"
}
if x > 1e12 {
return time.Unix(0, x*1e6).Format("2006-01-02 15:04:05")
}
return time.Unix(x, 0).Format("2006-01-02 15:04:05")
default:
return "N/A"
}
}
JSON 响应里的日期格式和模板无关,别混用
很多人把 API 返回的 JSON 时间格式问题(如 "2026-10-13T02:51:00+08:00")和 HTML 模板渲染混为一谈。这是两个独立环节:
- HTML 模板格式化只影响
c.HTML()渲染的页面内容 - JSON 格式由结构体 tag(
json:"created_at,time_format:\"2006-01-02 15:04:05\"")或自定义类型(如LocalTime)控制 - 改了模板函数,不影响
c.JSON()输出;反之亦然
如果你在同一个字段上既用于 HTML 渲染又用于 JSON 输出,建议统一用自定义类型(如 LocalTime),避免逻辑分散。
最容易被忽略的是时区——time.Unix(x, 0) 默认生成本地时区时间,但模板函数运行在服务器环境,若服务器时区非 CST,Format 结果会偏移。需要显式用 time.Unix(x, 0).In(loc) 转换,loc 应从配置读取,而非硬编码 time.Local。


















