Go语言GORM自定义时间格式:实现yyyy-MM-dd HH:mm:ss输出
在使用Go语言和GORM进行Web开发时,后端返回给前端的时间数据默认往往不符合人类阅读习惯(如RFC3339格式)。本文详细讲解如何定义自定义时间类型LocalTime,通过实现序列化与反序列化接口,将GORM查询结果中的时间统一格式化为"2006-01-02 15:04:05",确保API响应清晰且数据库读写正常。
问题背景
GORM默认基于Go标准库time.Time进行映射。当使用json.Marshal对包含时间的结构体进行序列化时,Go会输出标准的RFC3339Nano格式(例如:2022-12-06T17:49:06+08:00)。虽然该格式符合ISO标准,但在许多业务场景中,前端或用户更偏好简洁的yyyy-MM-dd HH:mm:ss格式。
直接修改time.Time的行为比较困难且容易引发不可预知的兼容性问题。最佳实践是创建一个类型别名,并在其上绑定自定义的方法。
解决方案:自定义LocalTime类型
我们需要定义一个新的类型LocalTime作为time.Time的别名,并实现三个关键接口:
MarshalJSON():控制序列化输出的JSON字符串格式。Value():实现driver.Valuer接口,控制写入数据库时的值格式。UnmarshalJSON():控制从JSON解析到本地对象时的反序列化逻辑。
第1步:定义结构与导入依赖
首先准备必要的包,包括GORM、MySQL驱动以及标准库中的编码和时间处理模块。
package main
import (
"database/sql/driver"
"encoding/json"
"fmt"
_ "github.com/go-sql-driver/mysql"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/schema"
"strings"
"time"
)
第2步:实现序列化方法 MarshalJSON
该方法将内部的时间转换为指定格式的字符串,并包裹双引号以符合JSON规范。
type LocalTime time.Time
func (t LocalTime) MarshalJSON() ([]byte, error) {
tTime := time.Time(t)
return []byte(fmt.Sprintf("\"%v\"", tTime.Format("2006-01-02 15:04:05"))), nil
}
第3步:实现数据库写入 Value
GORM在保存数据时会调用此方法。返回字符串格式可确保存入数据库的也是格式化后的时间(前提是数据库字段类型为datetime或varchar)。
func (t LocalTime) Value() (driver.Value, error) {
tTime := time.Time(t)
return tTime.Format("2006-01-02 15:04:05"), nil
}
第4步:实现反序列化 UnmarshalJSON
当接收到前端传来的JSON数据需要存回结构体时,此方法负责解析。注意去除首尾的双引号后解析时间。
func (t *LocalTime) UnmarshalJSON(data []byte) error {
if string(data) == "null" {
return nil
}
var err error
str := string(data)
// 去除接收的str收尾多余的"
timeStr := strings.Trim(str, "\"")
t1, err := time.Parse("2006-01-02 15:04:05", timeStr)
*t = LocalTime(t1)
return err
}
完整应用示例
下面是整合上述逻辑的完整代码,包含模型定义、数据库连接及测试打印。
type Student struct {
Id int
Name string
Age int
Sex string
CreateAt time.Time // 默认行为
}
func (Student) TableName() string {
return "student"
}
type StudentLocal struct {
Id int
Name string
Age int
Sex string
CreateAt LocalTime // 自定义行为
}
func (StudentLocal) TableName() string {
return "student"
}
var db *gorm.DB
var err error
func init() {
// dsn格式 user:pass@tcp(ip:port)/dbname?charset=utf8mb4&parseTime=True&loc=Local
dsn := "user:pass@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"
db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
NamingStrategy: schema.NamingStrategy{
TablePrefix: "",
SingularTable: true,
}})
if err != nil {
panic(err)
}
}
func main() {
// 1. 测试默认 Time 类型
var student Student
db.First(&student)
js, _ := json.Marshal(student)
fmt.Println("Default Time:", string(js))
// 输出类似: {"Id":1,"Name":"张三","Age":20,"Sex":"男","CreateAt":"2022-12-06T17:49:06+08:00"}
// 2. 测试自定义 LocalTime 类型
var studentLocal StudentLocal
db.First(&studentLocal)
js, _ = json.Marshal(studentLocal)
fmt.Println("Custom LocalTime:", string(js))
// 输出类似: {"Id":1,"Name":"张三","Age":20,"Sex":"男","CreateAt":"2022-12-06 17:49:06"}
// 3. 单独测试 Value 方法
value, _ := studentLocal.CreateAt.Value()
fmt.Println("DB Value:", value)
// 输出: 2022-12-06 17:49:06
}
注意事项
- DNS配置:在连接字符串中必须添加
&parseTime=True&loc=Local,否则GORM可能无法正确解析本地时区的时间。 - 时区处理:示例中使用了服务器本地时区(Local)。如果涉及跨时区业务,建议将
Format参数改为time.RFC3339或使用UTC格式存储,避免前端显示误差。 - 空值处理:在
UnmarshalJSON中处理了null情况,防止前端未传时间时报错。
以上就是Go语言中GORM自定义时间格式化的详细内容,更多关于Go GORM时间格式化的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













