前言

Gorm 中 time.Time 类型的字段在 JSON 序列化后呈现的格式为 "2020-03-11T18:26:13+08:00",在 Go 标准库文档 - time 的 MarshaJSON 方法 下面有这样一段描述:

MarshalJSON 实现了json.Marshaler 接口。返回值是用双引号括起来的采用 RFC 3339 格式进行格式化的时间表示,如果需要会提供小于秒的精度。

这个 RFC 3339 格式并不符合日常使用习惯,本文将介绍如何将其转换成常用的 "yyyy-MM-dd HH:mm:ss" 格式。

思路

在上一篇《Gorm 预加载及输出处理(二)- 查询输出处理》中,采用重写类型的 MarshaJSON 方法实现了自定义序列化输出,时间的自定义格式输出也采用这种方式,大致思路如下:

  1. 创建 time.Time 类型的副本 XTime;
  2. 为 Xtime 重写 MarshaJSON 方法,在此方法中实现自定义格式的转换;
  3. 为 Xtime 实现 Value 方法,写入数据库时会调用该方法将自定义时间类型转换并写入数据库;
  4. 为 Xtime 实现 Scan 方法,读取数据库时会调用该方法将时间数据转换成自定义时间类型;
  5. 自定义 BaseModel,结构和 gorm.Model 一致,将 time.Time 替换为 Xtime;
  6. 模型定义中使用 BaseModel 替代 gorm.Model;
  7. 模型定义中其他的 time.Time 类型字段也都使用 Xtime 替代。

实现

这里继续使用前两篇博文中的 User 模型:

// 用户模型
type User struct {
gorm.Model
Username string `gorm:"type:varchar(20);not null;unique"`
Email string `gorm:"type:varchar(64);not null;unique"`
Role string `gorm:"type:varchar(32);not null"`
Active *uint8 `gorm:"type:tinyint unsigned;default:1"`
Profile *Profile `gorm:"foreignkey:UserID;association_autoupdate:false"`
}

根据上述思路,逐步实现时间的自定义格式输出,为方便演示,以下代码均写在一个文件中,代码如下:

import (
"database/sql/driver"
"fmt"
"time"
) // 1. 创建 time.Time 类型的副本 XTime;
type XTime struct {
time.Time
} // 2. 为 Xtime 重写 MarshaJSON 方法,在此方法中实现自定义格式的转换;
func (t XTime) MarshalJSON() ([]byte, error) {
output := fmt.Sprintf("\"%s\"", t.Format("2006-01-02 15:04:05"))
return []byte(output), nil
} // 3. 为 Xtime 实现 Value 方法,写入数据库时会调用该方法将自定义时间类型转换并写入数据库;
func (t XTime) Value() (driver.Value, error) {
var zeroTime time.Time
if t.Time.UnixNano() == zeroTime.UnixNano() {
return nil, nil
}
return t.Time, nil
} // 4. 为 Xtime 实现 Scan 方法,读取数据库时会调用该方法将时间数据转换成自定义时间类型;
func (t *XTime) Scan(v interface{}) error {
value, ok := v.(time.Time)
if ok {
*t = XTime{Time: value}
return nil
}
return fmt.Errorf("can not convert %v to timestamp", v)
} // 5. 自定义 BaseModel,结构和 gorm.Model 一致,将 time.Time 替换为 Xtime;
type BaseModel struct {
ID uint `gorm:"primary_key"`
CreatedAt XTime
UpdatedAt XTime
DeletedAt *XTime `sql:"index"`
} // 6. 模型定义中使用 BaseModel 替代 gorm.Model;
// 用户模型
type User struct {
BaseModel
Username string `gorm:"type:varchar(20);not null;unique"`
Email string `gorm:"type:varchar(64);not null;unique"`
Role string `gorm:"type:varchar(32);not null"`
Active *uint8 `gorm:"type:tinyint unsigned;default:1"`
Profile *Profile `gorm:"foreignkey:UserID;association_autoupdate:false"`
} // 7. 模型定义中其他的 time.Time 类型字段也都使用 Xtime 替代。
// pass

简单测试下:

var users []*User

DB.Debug().Find(&users)

JSON 序列化输出如下:

[
{
"ID": 1,
"CreatedAt": "2020-03-11 18:26:13",
"UpdatedAt": "2020-03-11 19:00:00",
"DeletedAt": null,
"Username": "test",
"Email": "aaa@bbb.com",
"Role": "admin",
"Active": 1,
"Profile": null
},
{
"ID": 2,
"CreatedAt": "2020-03-11 19:46:21",
"UpdatedAt": "2020-03-11 19:46:21",
"DeletedAt": null,
"Username": "test2",
"Email": "bbb@ccc.com",
"Role": "admin",
"Active": 1,
"Profile": null
}
]

小结

其实只要理解了 go 的 JSON 序列化过程,就可以较为轻松地实现数据的自定义序列化。为需要自定义序列化的类型创建副本,重写 MarshalJSON 方法并在其中实现数据转换逻辑,基本就完事了。但也要注意是否需要为副本实现其他特定方法以保证其正常工作,例如,本文自定义时间类型 XTime 就需要实现 Value 和 Scan 方法,否则无法正常工作。

Gorm 自定义时间格式就介绍到这里,如发现任何问题,欢迎指正,谢谢观看!


本文出处:https://www.cnblogs.com/zhenfengxun/

本文链接:https://www.cnblogs.com/zhenfengxun/p/12548305.html

最新文章

  1. Linux下常见的IO模型
  2. httpModules与Http模块
  3. Android配置文件,所有权限
  4. 张艾迪(创始人):Hello.世界...
  5. CMD魔法堂:获取进程路径和PID值的方法集
  6. esayui-datagrid的使用
  7. ajax练习习题三搜索
  8. 数理方程:Fourier级数
  9. Shell语法中的test命令用法
  10. mysql命令行的基本用法
  11. 提交服务器 post get
  12. 【转】Python实现修改Windows CMD命令行输出颜色(完全解析)
  13. ios端position为fixed失效的解决办法
  14. webpack打包优化之外部扩展externals的实际应用
  15. Pytorch报错记录
  16. PHP和PHP-FPM 配置文件优化
  17. mysql 存储session
  18. Android逆向进阶(7)——揭开Hook的神秘面纱
  19. linux下如何源码安装expect
  20. 我的Apache又挂了之apache错误:server's fully qualified domain name, using 127.0.0.1. Set the 'ServerName'

热门文章

  1. SpringMVC学习笔记四:SimpleMappingExceptionResolver异常处理
  2. SpringMVC 数据校验(JSR-303)
  3. python Dom
  4. C++走向远洋——52(十三周阅读程序)
  5. flask 中文乱码
  6. 初学Qt——程序打包(环境vs2012+qt5.1.0)
  7. Python——详解collections工具库
  8. Think 框架漏洞利用
  9. LeetCode--二叉树1--树的遍历
  10. 查询mysql版本号