Golang 自定义Time类型的JSON字段格式
Go 自身的 time.Time 类型默认解析的日期格式是
RFC3339
标准, 也就是2006-01-02T15:04:05Z07:00
的格式。
改成自定义类型的思路是:
定义一个内嵌time.Time
的结构体,并重写MarshalJSON
方法,然后在定义model
的时候把time.Time
类型替换为我们自己的类型即可。
废话不多说,先上代码片段。
import (
"database/sql/driver"
"fmt"
"time"
)
const TimeFormat = "2006-01-02 15:04:05"
// JSONTime format json time field by myself
type JSONTime struct {
time.Time
}
func (t *JSONTime) UnmarshalJSON(data []byte) (err error) {
if len(data) == 2 {
*t = JSONTime{Time: time.Time{}}
return
}
loc, _ := time.LoadLocation("Asia/Shanghai")
now, err := time.ParseInLocation(`"`+TimeFormat+`"`, string(data), loc)
*t = JSONTime{Time: now}
return
}
// MarshalJSON on JSONTime format Time field with Y-m-d H:i:s
func (t JSONTime) MarshalJSON() ([]byte, error) {
if t.Time.IsZero() {
return []byte("null"), nil
}
formatted := fmt.Sprintf("\"%s\"", t.Format(TimeFormat))
return []byte(formatted), nil
}
// Value insert timestamp into mysql need this function.
func (t JSONTime) Value() (driver.Value, error) {
var zeroTime time.Time
if t.Time.UnixNano() == zeroTime.UnixNano() {
return nil, nil
}
return t.Time, nil
}
// Scan value of time.Time
func (t *JSONTime) Scan(v interface{}) error {
value, ok := v.(time.Time)
if ok {
*t = JSONTime{Time: value}
return nil
}
return fmt.Errorf("can not convert %v to timestamp", v)
}
- 在使用
gorm
框架时,用到MarshalJSON
/Scan
/Value
方法。 - 在使用
Gin
框架时使用ShouldBindJSON
绑定参数会调用UnmarshalJSON
,在context.ShouldBindJSON
时,会调用field.UnmarshalJSON
方法,context.JSON
返回 json 时,会调用field.MarshalJSON
方法。 - 在使用
go-redis
从缓存里取2021-08-26 12:00:00
格式的字符串时会调用UnmarshalJSON
不需要重新定义 string 类型的字段,解析到缓存数据之后再转成自定义time
类型。