go模板时间格式化函数必须在parse前注册到funcmap,且函数需导出、签名匹配;若参数非time.time类型会panic,应支持interface{}并做类型判断,时区处理需提前转换。

Go template 中时间格式化函数必须注册到 template.FuncMap
直接在 HTML 模板里用 {{ .CreatedAt | formatTime }} 会报错:「undefined function "formatTime"」。Go 的 html/template 默认不带任何时间处理函数,所有自定义函数都得手动注册进 template.FuncMap,且必须在调用 template.ParseFiles 或 template.Parse 之前完成。
常见错误是把函数注册写在模板渲染之后,或者漏传 FuncMap 给 template.New()。正确做法是:
- 定义函数,接收
time.Time(或int64、string等可转 time 的类型)并返回string - 构造
template.FuncMap,键为模板中使用的函数名(如"formatTime"),值为函数本身 - 用
template.New("name").Funcs(yourFuncMap)创建模板实例,再加载文件
示例:
func main() {
funcMap := template.FuncMap{
"formatTime": func(t time.Time) string {
return t.Format("2006-01-02 15:04:05")
},
}
tmpl := template.New("page").Funcs(funcMap)
tmpl, _ = tmpl.ParseFiles("views/index.html")
// ...
}
时间参数类型不匹配会导致 panic
模板里传入的不是 time.Time 类型时,比如后端传的是 Unix 时间戳 int64 或 ISO8601 字符串,直接调用 formatTime 会 panic:「interface conversion: interface {} is int64, not time.Time」。
解决方式不是让前端强制转 time,而是让模板函数自己兼容多种输入:
- 函数签名改为接收
interface{},内部用 type switch 判断 - 支持
time.Time、int64(秒级/毫秒级时间戳)、string(常见格式如 "2006-01-02T15:04:05Z") - 对字符串解析失败时,返回空字符串或 fallback 时间,避免模板渲染中断
精简版健壮函数示例:
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 > 1e10 { // ms timestamp
return time.Unix(x/1000, x%1000*1e6).Format("2006-01-02 15:04:05")
}
return time.Unix(x, 0).Format("2006-01-02 15:04:05")
case string:
if t, err := time.Parse(time.RFC3339, x); err == nil {
return t.Format("2006-01-02 15:04:05")
}
return x // fallback
default:
return ""
}
}
时区处理容易被忽略
Go 的 time.Time 带时区信息,但 Format 默认按本地时区输出。如果数据库存的是 UTC 时间,而你希望页面显示用户本地时间(如 CST),不能靠前端 JS 转换——模板渲染阶段就得处理。
两种常用方案:
- 统一转成指定时区再格式化,例如
t.In(time.Local).Format(...)(依赖服务器TZ环境变量) - 传入时区名作为第二个参数,如
{{ .CreatedAt | formatTime "Asia/Shanghai" }},函数内部用time.LoadLocation解析并转换
注意:time.LoadLocation 有开销,建议缓存结果;多次调用 time.LoadLocation("Asia/Shanghai") 不推荐。
Beego / Gin / Echo 等框架中注册位置有差异
不同框架封装程度不同,注册时机和入口点不一样:
-
Gin:通常在初始化模板引擎时注册,用
engine.SetFuncMap(),必须在LoadHTMLGlob之前 -
Beego:通过
beego.AddFuncMap("formatTime", fn),全局生效,可在main()早期调用 -
Echo:需自己构建
html/template实例,再传给echo.Renderer,FuncMap 在模板创建时注入
最容易出错的是 Gin:很多人把 SetFuncMap 写在 engine.LoadHTMLGlob(...) 之后,导致函数不可用,且无明确报错,只会渲染为空白。
真正麻烦的不是写函数,而是确保它在模板解析前就位、能处理各种输入类型、并且时区逻辑和业务需求对齐。模板函数一旦上线,改起来牵一发而动全身——尤其是当多个页面共用同一个格式化逻辑时。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











