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

Stella981
• 阅读 1889

定义模型

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

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
2年前
java将前端的json数组字符串转换为列表
记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
2年前
JS 对象数组Array 根据对象object key的值排序sort,很风骚哦
有个js对象数组varary\{id:1,name:"b"},{id:2,name:"b"}\需求是根据name或者id的值来排序,这里有个风骚的函数函数定义:function keysrt(key,desc) {  return function(a,b){    return desc ? ~~(ak
Wesley13 Wesley13
2年前
MySql 相关函数
SELECTGROUP\_CONCAT(column\_name)FROMtable\_namegroupbytable\_name,table\_name2...FIELD()函数自定义排序select\fromuserwheretypein(1,2,3)orderbyFIELD(column,str1,st
Wesley13 Wesley13
2年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这