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/

posted @ 2019-10-17 22:18  jssyjam  阅读(6558)  评论(0编辑  收藏  举报