• 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"`
    }
    

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

    解决CreatedAtUpdatedAtDeletedAt输出

    官方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)
    }
    

    这样解决了CreatedAtUpdatedAtDeletedAt的问题。
    但是使用类似

    	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时区

  • 相关阅读:
    我为什么支持从中学课本中撤下鲁迅的文章?
    【老孙随笔】技术不行别人就不服你,怎么办?
    【老孙随笔】求职,不要无的放矢
    读者来信(1)——项目经理,不要迷信制度!
    欣闻鲁迅文章下架
    知道力读书会,欢迎大家参加
    【老孙随笔】是谁杀死了QQ?
    技术,项目经理的命?——项目经理的误区(3)
    可以不封神,但是不能不修炼——亚特兰蒂斯之神特斯拉的启示
    分布式开发2WCF如何正确调用LINQTO SQL
  • 原文地址:https://www.cnblogs.com/mrylong/p/11326792.html
Copyright © 2020-2023  润新知