go mysql datetime_Gorm 对mysql的datetime类型特殊的格式化问题

定义模型

type ProgramModel struct {

gorm.Model

Name string `json:"name" gorm:"column:name"`

StartTime string `json:"start_time" gorm:"column:start_time"`

EndTime string `json:"end_time" gorm:"column:end_time"`

}

其中gorm.Model内容如下

type Model struct {

ID uint `gorm:"primary_key"`

CreatedAt time.Time

UpdatedAt time.Time

DeletedAt *time.Time `sql:"index"`

}

ProgramModel的StartTime、EndTime、CreatedAt、UpdatedAt、DeletedAt在数据库中是datetime类型,但是输出却是2019-08-09T11:35:52+08:00,如果希望得到2019-08-09 11:35:52这种输出怎么办呢?

解决CreatedAt、UpdatedAt、DeletedAt输出

官方github的Issuse中有类似问题参考链接,使用自定义结构BaseModel代替gorm.Model

type ProgramModel struct {

BaseModel

Name string `json:"name" gorm:"column:name"`

StartTime BaseModel `json:"start_time" gorm:"column:start_time"`

EndTime BaseModel `json:"end_time" gorm:"column:end_time"`

}

type BaseModel struct {

gorm.Model

Id uint64 `gorm:"primary_key;AUTO_INCREMENT;column:id" json:"id"`

CreatedAt MyTime `gorm:"column:create_time" json:"create_time"`

UpdatedAt MyTime `gorm:"column:update_time" json:"update_time"`

}

type MyTime struct {

time.Time

}

func (t MyTime) MarshalJSON() ([]byte, error) {

formatted := fmt.Sprintf("\"%s\"", t.Format(timeFormat))

return []byte(formatted), nil

}

func (t MyTime) Value() (driver.Value, error) {

var zeroTime time.Time

if t.Time.UnixNano() == zeroTime.UnixNano() {

return nil, nil

}

return t.Time, nil

}

func (t *MyTime) Scan(v interface{}) error {

value, ok := v.(time.Time)

if ok {

*t = MyTime{Time: value}

return nil

}

return fmt.Errorf("can not convert %v to timestamp", v)

}

这样解决了CreatedAt、UpdatedAt、DeletedAt的问题。

但是使用类似

testStr := `{

"name": "test",

"start_time": "2019-08-09 10:00:23",

"end_time": "2019-08-09 11:00:23"

}`

var obj ProgramModel

if err := json.Unmarshal([]byte(testStr), &obj); err != nil {

panic(err)

}

来创建数据时候却不行,我又不想再定义一个结构体接收之后在后转换

解决StartTime、EndTime的输出

修改配置

去掉链接数据库配置的parseTime=%t&loc=%s;最后就是

config := fmt.Sprintf("%s:%s@(%s:%s)/%s?charset=utf8",

username,

password,

addr,

port,

name)

将所有时间字段全部改为string类型。如下

type BaseModel struct {

gorm.Model

Id uint64 `gorm:"primary_key;AUTO_INCREMENT;column:id" json:"id"`

CreatedAt string `gorm:"column:create_time" json:"create_time"`

UpdatedAt string `gorm:"column:update_time" json:"update_time"`

}

type ProgramModel struct {

BaseModel

Name string `json:"name" gorm:"column:name"`

StartTime string `json:"start_time" gorm:"column:start_time"`

EndTime string `json:"end_time" gorm:"column:end_time"`

}

这样就就可以了,但是UpdatedAt这个字段无法自动更新。可以添加如下方法,这样每次更新时候都会调用该方法

func (v BaseModel) BeforeCreate(scope *gorm.Scope) error {

scope.SetColumn("create_time", NowTime())

scope.SetColumn("update_time", NowTime())

return nil

}

func (v BaseModel) BeforeUpdate(scope *gorm.Scope) error {

scope.SetColumn("update_time", NowTime())

return nil

}

关于 gorm的parseTime和loc

parseTime是自动转换为时间

go使用RFC3339Nano这个格式来Marshal时间

// MarshalJSON implements the json.Marshaler interface.

// The time is a quoted string in RFC 3339 format, with sub-second precision added if present.

func (t Time) MarshalJSON() ([]byte, error) {

if y := t.Year(); y < 0 || y >= 10000 {

// RFC 3339 is clear that years are 4 digits exactly.

// See golang.org/issue/4556#c15 for more discussion.

return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")

}

b := make([]byte, 0, len(RFC3339Nano)+2)

b = append(b, '"')

b = t.AppendFormat(b, RFC3339Nano)

b = append(b, '"')

return b, nil

}

所以才有上面自定义类型,自定义MarshalJSON方法。

loc是 MySQL的时区设置

mysql> show variables like "%time_zone%";

+------------------+--------+

| Variable_name | Value |

+------------------+--------+

| system_time_zone | CST |

| time_zone | SYSTEM |

+------------------+--------+

2 rows in set (0.04 sec)

time_zone说明mysql使用system的时区;system_time_zone说明system使用CST时区

你可能感兴趣的:(go,mysql,datetime)