gorm 重写time.Time

1,110 阅读3分钟

gorm 的time.Time 显示特别不直观,总是展示什么带T的字符。

因而重写了 time.Time 的输入输出接口。

建议采用第一种方法,该方法在前端返回字符串,后端储存如2022-07-23 01:09:27 的日期字段,比较直观。

方法一,采用潜在类型:

type Time time.Time

// UnmarshalJSON 1. 为 Xtime 重写 UnmarshalJSON 方法,在此方法中实现自定义格式的转换;
func (t *Time) UnmarshalJSON(data []byte) (err error) {
   num, err := strconv.Atoi(string(data))
   if err != nil {
      return err
   }
   *t = Time(time.Unix(int64(num), 0))
   return
}

// MarshalJSON 2. 为 Xtime 重写 MarshaJSON 方法,在此方法中实现自定义格式的转换;
func (t Time) MarshalJSON() ([]byte, error) {
   return ([]byte)(strconv.FormatInt(time.Time(t).Unix(), 10)), nil
}

// Value 3. 为 Time 实现 Value 方法,写入数据库时会调用该方法将自定义时间类型转换并写入数据库;
func (t Time) Value() (driver.Value, error) {
   var zeroTime time.Time
   if time.Time(t).Unix() == zeroTime.UnixNano() {
      return nil, nil
   }
   return time.Time(t), nil
}

// Scan 4. 为 Time 实现 Scan 方法,读取数据库时会调用该方法将时间数据转换成自定义时间类型;
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)
}

方法二,创建匿名继承类:

/*-----------------------------------------*/
/*---    XTime 时间设定          -----------*/

type XTime struct {
   time.Time
}

var ExTimeUnmarshalTimeFormat = "2006-01-02 15:04:05"
var ExTimeMarshalTimeFormat = "2006-01-02 15:04:05"

func (t XTime) UnmarshalTimeFormat() string {
   return ExTimeUnmarshalTimeFormat
}

func (t XTime) MarshalTimeFormat() string {
   return ExTimeMarshalTimeFormat
}

// UnmarshalJSON 1. 为 Xtime 重写 UnmarshalJSON 方法,在此方法中实现自定义格式的转换;
func (t *XTime) UnmarshalJSON(b []byte) error {
   b = bytes.Trim(b, "")   // 此除需要去掉传入的数据的两端的 ""
   ext, err := time.Parse(t.UnmarshalTimeFormat(), string(b))
   if err != nil {
      // do something
   }
   *t = XTime{ext}
   return nil
}

// MarshalJSON 2. 为 Xtime 重写 MarshaJSON 方法,在此方法中实现自定义格式的转换;
func (t XTime) MarshalJSON() ([]byte, error) {
   output := fmt.Sprintf("%s", t.Format("2006-01-02 15:04:05"))
   return []byte(output), nil
}

// Value 3. 为 Xtime 实现 Value 方法,写入数据库时会调用该方法将自定义时间类型转换并写入数据库;
func (t XTime) Value() (driver.Value, error) {
   var zeroTime time.Time
   if t.Time.UnixNano() == zeroTime.UnixNano() {
      return nil, nil
   }
   return t.Time, nil
}

// Scan 4. 为 Xtime 实现 Scan 方法,读取数据库时会调用该方法将时间数据转换成自定义时间类型;
func (t *XTime) Scan(v interface{}) error {
   value, ok := v.(time.Time)
   if ok {
      *t = XTime{Time: value}
      return nil
   }
   return fmt.Errorf("can not convert %v to timestamp", v)
}

/*---    XTime 时间设定结束      ------------*/
/*-----------------------------------------*/

重写的BaseModel如下:

package baseModel

import (
   "database/sql/driver"
   "encoding/json"
   "fmt"
   "gorm.io/gorm"
   "strconv"
   "time"
)

type BaseModel struct {
   ID        uint           `json:"ID" gorm:"primarykey"`
   CreatedAt Time           `json:"CreatedAt" gorm:"column:createdat"`
   UpdatedAt Time           `json:"UpdatedAt" gorm:"column:updatedat"`
   DeletedAt gorm.DeletedAt `json:"DeletedAt" gorm:"column:deletedat"`
}

type Time time.Time

// UnmarshalJSON 1. 为 Time 重写 UnmarshalJSON 方法,在此方法中实现自定义格式的转换;
func (t *Time) UnmarshalJSON(data []byte) (err error) {
   num, err := strconv.Atoi(string(data))
   if err != nil {
      return err
   }
   *t = Time(time.Unix(int64(num), 0))
   return
}

// MarshalJSON 2. 为 Time 重写 MarshaJSON 方法,在此方法中实现自定义格式的转换;
func (t Time) MarshalJSON() ([]byte, error) {
   return ([]byte)(strconv.FormatInt(time.Time(t).Unix(), 10)), nil
}

// Value 3. 为 Time 实现 Value 方法,写入数据库时会调用该方法将自定义时间类型转换并写入数据库;
func (t Time) Value() (driver.Value, error) {
   var zeroTime time.Time
   if time.Time(t).Unix() == zeroTime.UnixNano() {
      return nil, nil
   }
   return time.Time(t), nil
}

// Scan 4. 为 Time 实现 Scan 方法,读取数据库时会调用该方法将时间数据转换成自定义时间类型;
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)
}

const (
   timeFormart = "2006-01-02 15:04:05"
)

func (t Time) String() string {
   b := make([]byte, 0, len(timeFormart))
   b = time.Time(t).AppendFormat(b, timeFormart)
   return string(b)
}

/*-----------------------------------------*/
/*---    []uint 设定               -----------*/

type UintArray []uint

// 入库。实现 driver.Valuer 接口,Value 返回 json value
func (j UintArray) Value() (driver.Value, error) {
   if len(j) == 0 {
      return "", nil
   }
   marshal, err := json.Marshal(j)
   if err != nil {
      return "", nil
   }
   return string(marshal), nil
}

// 出库。实现 sql.Scanner 接口,Scan 将 value 扫描至 Jsonb
func (j *UintArray) Scan(value interface{}) error {
   uintBytes, ok := value.([]byte)
   if !ok || len(uintBytes) == 0 {
      return nil
   }
   result := UintArray{}
   err := json.Unmarshal(uintBytes, &result)
   *j = result
   return err
}

/*---   []unit 时间设定结束      ------------*/
/*-----------------------------------------*/