gorm 处理时间戳

问题

在使用 gorm 的过程中, 处理时间戳字段时遇到问题。写时间戳到数据库时无法写入。

通过查阅资料最终问题得以解决,特此总结

设置数据库的 dsn

parseTime = "True"
loc = "Local"

设置自定义 Time 类型

package types

import (
    "database/sql/driver"
    "fmt"
    "time"
)

// Time is alias type for time.Time
type Time time.Time

const (
    timeFormart = "2006-01-02 15:04:05"
    zone        = "Asia/Shanghai"
)

// UnmarshalJSON implements json unmarshal interface.
func (t *Time) UnmarshalJSON(data []byte) (err error) {
    now, err := time.ParseInLocation(`"`+timeFormart+`"`, string(data), time.Local)
    *t = Time(now)
    return
}

// MarshalJSON implements json marshal interface.
func (t Time) MarshalJSON() ([]byte, error) {
    b := make([]byte, 0, len(timeFormart)+2)
    b = append(b, '"')
    b = time.Time(t).AppendFormat(b, timeFormart)
    b = append(b, '"')
    return b, nil
}

func (t Time) String() string {
    return time.Time(t).Format(timeFormart)
}

func (t Time) local() time.Time {
    loc, _ := time.LoadLocation(zone)
    return time.Time(t).In(loc)
}

// Value ...
func (t Time) Value() (driver.Value, error) {
    var zeroTime time.Time
    var ti = time.Time(t)
    if ti.UnixNano() == zeroTime.UnixNano() {
        return nil, nil
    }
    return ti, nil
}

// Scan valueof time.Time 注意是指针类型 method
func (t *Time) Scan(v interface{}) error {
    value, ok := v.(time.Time)
    if ok {
        *t = Time(value)
        return nil
    }
    return fmt.Errorf("can not convert %v to timestamp", v)
}

这样程序中所有的时间值都使用types.Time类型就可以准确进行时间戳变量的读写操作。

原理

其实就是自定义数据库数据类型,在 sql driver 中实现自定义类型需要实现 ScannerValuer接口

Scanner

type Scanner interface {
    Scan(src interface{}) error
}

Valuer

type Valuer interface {
    // Value returns a driver Value.
    Value() (Value, error)
}

unmarshalmarshal 自定义 json 转换格式

参考

https://reading.developerlearning.cn/discuss/2019-06-19-gorm-mysql-timestamp/

猜你喜欢

转载自www.cnblogs.com/jssyjam/p/11695502.html