【Golang】Go中時間(time)的用法以及gorm處理時間戳


time包提供了時間的顯示和測量用的函數。日歷的計算采用的是公歷。 time 類型

type Time struct {
// wall and ext encode the wall time seconds, wall time nanoseconds,
// and optional monotonic clock reading in nanoseconds.
//
// From high to low bit position, wall encodes a 1-bit flag (hasMonotonic),
// a 33-bit seconds field, and a 30-bit wall time nanoseconds field.
// The nanoseconds field is in the range [0, 999999999].
// If the hasMonotonic bit is 0, then the 33-bit field must be zero
// and the full signed 64-bit wall seconds since Jan 1 year 1 is stored in ext.
// If the hasMonotonic bit is 1, then the 33-bit field holds a 33-bit
// unsigned wall seconds since Jan 1 year 1885, and ext holds a
// signed 64-bit monotonic clock reading, nanoseconds since process start.
wall uint64
ext  int64

	// loc specifies the Location that should be used to
	// determine the minute, hour, month, day, and year
	// that correspond to this Time.
	// The nil location means UTC.
	// All UTC times are represented with loc==nil, never loc==&utcLoc.
	loc *Location
}

time可以精確到納秒, 下面是各種時間換

package main

import (
	"fmt"
	"time"
)

func main() {
	t := time.Now()
	fmt.Println(t)        //獲取當前時間2021-09-23 10:55:44.831571 +0800 CST m=+0.000090412
	fmt.Println(t.Unix()) //獲取當前時間時間戳 1632366278
	//fmt.Println(t.UnixMilli()) //獲取當前時間毫秒 1632366278605
	//fmt.Println(t.UnixMicro()) //獲取當前時間微秒 1632366278605122
	fmt.Println(t.UnixNano()) //獲取當前時間時納秒 1632366278605122000
	fmt.Println(t.Hour())     //獲取當前小時 10
	fmt.Println(t.Day())      //獲取當前天 23
	fmt.Println(t.Weekday())  //獲取當前周Thursday
	fmt.Println(t.ISOWeek())  //獲取當前周2021 38

	//格式化當前時間表示
	fmt.Println(t.String())                      //字符型
	fmt.Println(t.Format("2006-01-02 15:04:05")) //2021-09-23 11:12:42
	fmt.Println(t.Format("2006-01-02"))          //2021-09-23
	fmt.Println(t.Format("15:04:05"))            //11:12:42

	//指定時間戳轉換
	fmt.Println(time.Unix(1632366278, 0).Format("2006-01-02 15:04:05")) //2021-09-23 11:04:38
	//指定時間轉時間戳
	tm2, _ := time.Parse("2006-01-02 15:04:05", "2021-09-23 11:04:38")
	fmt.Println(tm2.Unix()) //1632395078

	//"2021-09-08T08:18:46+08:00" 轉2021-09-08 08:18:46
	t, _ = time.Parse(time.RFC3339, "2021-09-08T08:18:46+08:00")
	fmt.Println(t.Format("2006-01-02 15:04:05"))
	//2021-09-07T17:01:34.182659088Z 轉2021-09-07 17:01:34
	t, _ = time.Parse(time.RFC3339Nano, "2021-09-07T17:01:34.182659088Z")
	fmt.Println(t.Format("2006-01-02 15:04:05"))
	//其他格式類似可參考

	//ANSIC       = "Mon Jan _2 15:04:05 2006"
	//UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
	//RubyDate    = "Mon Jan 02 15:04:05 -0700 2006"
	//RFC822      = "02 Jan 06 15:04 MST"
	//RFC822Z     = "02 Jan 06 15:04 -0700" // 使用數字表示時區的RFC822
	//RFC850      = "Monday, 02-Jan-06 15:04:05 MST"
	//RFC1123     = "Mon, 02 Jan 2006 15:04:05 MST"
	//RFC1123Z    = "Mon, 02 Jan 2006 15:04:05 -0700" // 使用數字表示時區的RFC1123
	//RFC3339     = "2006-01-02T15:04:05Z07:00"
	//RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
	//Kitchen     = "3:04PM"
	//// 方便的時間戳
	//Stamp      = "Jan _2 15:04:05"
	//StampMilli = "Jan _2 15:04:05.000"
	//StampMicro = "Jan _2 15:04:05.000000"
	//StampNano  = "Jan _2 15:04:05.000000000"

	//設置時區 Location
	//默認UTC
	loc, _ := time.LoadLocation("")
	// 服務器設定的時區,一般為CST
	//loc, _ := time.LoadLocation("Local")
	//loc, _ := time.LoadLocation("Asia/Shanghai")
	t.In(loc).Format("2006-01-02 15:04:05")

	//1.5s后
	now := time.Now()
	tp, _ := time.ParseDuration("1.5s")
	fmt.Println(tp, tp.Truncate(1000), tp.Seconds(), tp.Nanoseconds())
	m1 := now.Add(tp)
	fmt.Println(m1) //2021-09-23 14:30:42.006213 +0800 CST m=+1.500352171

	//1個小時前
	tp, _ = time.ParseDuration("-1h")

	m1 = now.Add(tp)
	fmt.Println(m1) //2021-09-23 13:30:40.506213 +0800 CST m=-3599.999647829
	//休眠時間
	//time.Sleep(time.Duration(10) * time.Second)

	// func After(d Duration) <-chan Time  非阻塞,可用於延遲
	//time.After(time.Duration(10) * time.Second)

	// func Since(t Time) Duration 兩個時間點的間隔
	start := time.Now()
	fmt.Println(time.Since(start)) // 等價於 Now().Sub(t), 可用來計算一段業務的消耗時間

	//func Until(t Time) Duration     //  等價於 t.Sub(Now()),t與當前時間的間隔

	time3 := "2021-03-20 08:50:29"
	time4 := "2021-03-20 08:50:29"
	//先把時間字符串格式化成相同的時間類型
	t3, _ := time.Parse("2006-01-02 15:04:05", time3)
	t4, _ := time.Parse("2006-01-02 15:04:05", time4)

	fmt.Println(t3.Equal(t4)) //true

	now = time.Now()
	//Ticker 類型包含一個 channel,有時我們會遇到每隔一段時間執行的業務(比如設置心跳時間等),就可以用它來處理,這是一個重復的過程

	// 無法取消
	//tick := time.Tick(1 * time.Minute)
	//for _ = range tick {
	//	// do something
	//}
	//NewTicker返回一個新的Ticker,該Ticker包含一個通道字段,並會每隔時間段d就向該通道發送當時的時間。它會調整時間間隔或者丟棄tick信息以適應反應慢的接收者。如果d<=0會panic。關閉該Ticker可以釋放相關資源。
	// 可通過調用ticker.Stop取消
	//創建一個周期性的定時器
	//設置定時器為3秒
	timer := time.NewTimer(3 * time.Second)
	fmt.Println("當前時間為:", time.Now())

	t = <-timer.C //從定時器拿數據
	fmt.Println("當前時間為:", t)
	timer.Stop() //停止

}

 

問題:在使用 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 轉換格式


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM