問題
在使用 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 中實現自定義類型需要實現 Scanner
和Valuer
接口
Scanner
type Scanner interface {
Scan(src interface{}) error
}
Valuer
type Valuer interface {
// Value returns a driver Value.
Value() (Value, error)
}
unmarshal
和marshal
自定義 json 轉換格式
參考
https://reading.developerlearning.cn/discuss/2019-06-19-gorm-mysql-timestamp/