GO項目實戰之Gorm格式化時間字段實現

goshop開源項目的更新

備註:前面項目中用到的代碼已經分享到GitHub中去瞭,並且以後所有項目中會出現的代碼都會提交上去,歡迎查閱。感興趣的可以點個star哦~
https://gitee.com/jobhandsome/goshop/

在使用 gorm 查詢時,如果未對時間字段進行處理,結構體內的字段類型咱們使用的是 time.Time

type Model struct {
    ID        int64      `json:"id" gorm:"primary_key"`
    CreatedAt *time.Time `json:"created_at"`
    UpdatedAt *time.Time `json:"updated_at"`
    DeletedAt *time.Time `json:"deleted_at" sql:"index"`
}

這裡咱們使用 time.Time 類型在 gorm 進行查詢的返回結果,讀取到的時間字段往往是這樣:“2022-07-03T22:14:02.973528+08:00”,帶著時區和毫秒。但其實往往這樣的格式,不是咱們想要的。

那麼問題就來瞭:

  1. 如果想要 “2022-07-03 22:14:02” 這樣的格式,需要怎麼處理呢?
  2. 當插入一條數據到對應的表中時,UpdateAt 字段是不賦值的,插入到數據庫則會 0001-01-01 00:00:00.000000+00:00,系統賦瞭⼀個默認值,當不想插⼊默認值時如何處理?

通過上面的分析,咱們能確定兩個需求:

讀取到的時間需要是:“2022-07-03 22:14:02” 這樣的格式

當時間字段不賦值時,不插入默認值

解決方法:

定義一個時間類型 struct

type LocalTime time.Time

雖然該數據類型實際類型為 time.Time,但是不具備 time.Time 的內置⽅法,需要重寫 MarshalJSON ⽅法來實現數據解析

func (t *LocalTime) MarshalJSON() ([]byte, error) {
    tTime := time.Time(*t)
    return []byte(fmt.Sprintf("\"%v\"", tTime.Format("2006-01-02 15:04:05"))), nil
}

註意:GO的格式化時間的規定時間字符串必須為 2006-01-02 15:04:05
這是GO的誕⽣時間,不能更改為其他時間(這個時間字符串與java的"yyyy-MM-dd HH:mm:ss")同作⽤

time.Time 替換成 LocalTime

type Model struct {
    ID        int64      `json:"id" gorm:"primary_key"`
    CreatedAt *LocalTime `json:"created_at"`
    UpdatedAt *localTime `json:"updated_at"`
    DeletedAt *localTime `json:"deleted_at" sql:"index"`
}

到瞭這一步就解決瞭第一個需求讀取數據時將將時間數據格式化。

下面來實現第二個需求:

func (t LocalTime) Value() (driver.Value, error) {
    var zeroTime time.Time
    tlt := time.Time(t)
    //判斷給定時間是否和默認零時間的時間戳相同
    if tlt.UnixNano() == zeroTime.UnixNano() {
        return nil, nil
    }
    return tlt, nil
}

Value⽅法即在存儲時調⽤,將該⽅法的返回值進⾏存儲,該⽅法可以實現數據存儲前對數據進⾏相關操作。

func (t *LocalTime) Scan(v interface{}) error {
    if value, ok := v.(time.Time); ok {
        *t = LocalTime(value)
        return nil
    }
    return fmt.Errorf("can not convert %v to timestamp", v)
}

Scan⽅法可以實現在數據查詢出來之前對數據進⾏相關操作。

到瞭這一步,咱們就實現瞭上面需求的功能。

補充:gorm時間格式化問題詳解

說明

在做項目時發現gorm的時間格式是帶有時區輸入輸出的,對平常使用的2020-01-03 12:22:33格式有一定的出入,不方便前端和後端的對接,所以自己整理一下處理這個問題方法,方便大傢參考

代碼如下

package models

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

//BaseModel 基礎結構體 信息信息
type BaseModel struct {
	CreateTime MyTime `gorm:"comment:'創建時間';type:timestamp;";json:"createTime"`
	UpdateTime MyTime `gorm:"comment:'修改時間';type:timestamp;";json:"updateTime"`
	Remark     string `gorm:"comment:'備註'";json:"remark"`
}
//MyTime 自定義時間
type MyTime time.Time

func (t *MyTime) UnmarshalJSON(data []byte) error {
	if string(data) == "null" {
		return nil
	}
	var err error
	//前端接收的時間字符串
	str := string(data)
	//去除接收的str收尾多餘的"
	timeStr := strings.Trim(str, "\"")
	t1, err := time.Parse("2006-01-02 15:04:05", timeStr)
	*t = MyTime(t1)
	return err
}

func (t MyTime) MarshalJSON() ([]byte, error) {
	formatted := fmt.Sprintf("\"%v\"", time.Time(t).Format("2006-01-02 15:04:05"))
	return []byte(formatted), nil
}

func (t MyTime) Value() (driver.Value, error) {
	// MyTime 轉換成 time.Time 類型
	tTime := time.Time(t)
	return tTime.Format("2006-01-02 15:04:05"), nil
}

func (t *MyTime) Scan(v interface{}) error {
	switch vt := v.(type) {
	case time.Time:
		// 字符串轉成 time.Time 類型
		*t = MyTime(vt)
	default:
		return errors.New("類型處理錯誤")
	}
	return nil
}

func (t *MyTime) String() string {
	return fmt.Sprintf("hhh:%s", time.Time(*t).String())
}

實現原理

其實現方式其實是通過在時間讀取json時對解析格式進行重寫,對轉換成字符串時進行重寫達到效果

總結

到此這篇關於GO項目實戰之Gorm格式化時間字段實現的文章就介紹到這瞭,更多相關GO Gorm格式化時間字段內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: