一文帶你理解Golang中的Time結(jié)構(gòu)
在golang中創(chuàng)建并打印一個(gè)時(shí)間對象,會看到如下輸出
2018-10-26 14:15:50.306558969 +0800 CST m=+0.000401093
前面表示的意義好理解,分別是年月日和時(shí)間時(shí)區(qū),最后的m=+xxxx這部分代表什么呢?
Monotonic Clocks 和 Wall Clocks
根據(jù)golang的time包的文檔可以知道,golang的time結(jié)構(gòu)中存儲了兩種時(shí)鐘,一種是Wall Clocks,一種是Monotonic Clocks。
Wall Clocks,顧名思義,表示墻上掛的鐘,在這里表示我們平時(shí)理解的時(shí)間,存儲的形式是自 1970 年 1 月 1 日 0 時(shí) 0 分 0 秒以來的時(shí)間戳,當(dāng)系統(tǒng)和授時(shí)服務(wù)器進(jìn)行校準(zhǔn)時(shí)間時(shí)間操作時(shí),有可能造成這一秒是2018-1-1 00:00:00,而下一秒變成了2017-12-31 23:59:59的情況。Monotonic Clocks,意思是單調(diào)時(shí)間的,所謂單調(diào),就是只會不停的往前增長,不受校時(shí)操作的影響,這個(gè)時(shí)間是自進(jìn)程啟動以來的秒數(shù)。
如果每隔一秒生成一個(gè)Time并打印出來,就會看到如下輸出。
2018-10-26 14:15:50.306558969 +0800 CST m=+0.000401093
2018-10-26 14:15:51.310559881 +0800 CST m=+1.004425285
2018-10-26 14:15:52.311822486 +0800 CST m=+2.005711106
2018-10-26 14:15:53.314599457 +0800 CST m=+3.008511329
2018-10-26 14:15:54.31882248 +0800 CST m=+4.012757636
2018-10-26 14:15:55.320059921 +0800 CST m=+5.014018292
2018-10-26 14:15:56.323814998 +0800 CST m=+6.017796644
2018-10-26 14:15:57.324858749 +0800 CST m=+7.018863606
2018-10-26 14:15:58.325164174 +0800 CST m=+8.019192224
2018-10-26 14:15:59.329058535 +0800 CST m=+9.023109863
2018-10-26 14:16:00.329591268 +0800 CST m=+10.023665796
可以看到m=+后面所顯示的數(shù)字,就是文檔中所說的Monotonic Clocks。
Time結(jié)構(gòu)
那么Monotonic Clock和Wall Clock在Time中是怎么存儲的呢?來看一下Time結(jié)構(gòu)體。
type Time struct { wall uint64 ext int64 loc *Location }
Time結(jié)構(gòu)體中由三部分組成,loc比較明了,表示時(shí)區(qū),wall和ext所存儲的信息規(guī)則相對復(fù)雜,根據(jù)文檔的介紹總結(jié)成了下圖:
golang中的Time結(jié)構(gòu),不像很多語言保存Unix時(shí)間戳(也就是最早只能表示到1970年1月1日),而是至少可以安全的表示1885年以來的時(shí)間。
t, _ := time.Parse(time.RFC3339, "1890-01-02T15:04:05Z") fmt.Println(t) // 1890-01-02 15:04:05 +0000 UTC
實(shí)踐中需要注意的問題
既然Time結(jié)構(gòu)所表示的時(shí)間,有可能有Monotonic Clock也可能沒有,那么在使用中就有可能遇到一些問題,例如下面這種情況。
now := time.Now() encodeNow, _ := json.Marshal(now) decodeNow := time.Time{} json.Unmarshal(encodeNow, &decodeNow) fmt.Println(now) // 2018-10-26 16:04:55.230121766 +0800 CST m=+0.000520419 fmt.Println(decodeNow) // 2018-10-26 16:04:55.230121766 +0800 CST
可以看到,經(jīng)過JSON轉(zhuǎn)碼之后,Time結(jié)構(gòu)體會被表示成不帶Monotonic Clock的字符串,丟失了Monotonic Clock信息,而將字符串轉(zhuǎn)碼回Time結(jié)構(gòu)時(shí),自然也就和轉(zhuǎn)碼之前的不一樣了。同樣的情況,也發(fā)生在數(shù)據(jù)庫存儲中,存儲到數(shù)據(jù)庫里的Time結(jié)構(gòu)和從數(shù)據(jù)庫取出來的也是不一樣的。
當(dāng)調(diào)用Equal比較兩個(gè)Time時(shí),只有兩個(gè)Time都含有Monotonic Clock時(shí),才會根據(jù)Monotonic Clock比較大小,其他情況只比較Wall Clock部分。
timeA := time.Now() timeB := time.Unix(0, timeA.UnixNano()) fmt.Println(timeA) // 2018-10-26 16:37:02.216165074 +0800 CST m=+0.000363156 fmt.Println(timeB) // 2018-10-26 16:37:02.216165074 +0800 CST r := timeA.Equal(timeB) fmt.Println(r) // true
上面兩個(gè)時(shí)間的Wall Clock部分相同,一個(gè)有Monotonic Clock一個(gè)沒有,但是比較的結(jié)果是兩個(gè)時(shí)間是相同的。
timeA := time.Now() timeB := time.Unix(timeA.Unix(), 0) fmt.Println(timeA) // 2018-10-26 16:38:25.653953438 +0800 CST m=+0.000364851 fmt.Println(timeB) // 2018-10-26 16:38:25 +0800 CST r := timeA.Equal(timeB) fmt.Println(r) // false
需要注意的是Wall Clock并不是秒之前的部分,Wall Clock本身也可以精確到納秒級別,所以一個(gè)精確到納秒的時(shí)間和一個(gè)精確到秒的時(shí)間也是不同的。
對于Time中的Monotonic Clock,我們可以使用time.Round(0)
方法將其消除掉,以實(shí)現(xiàn)和其他語言一致的行為。
timeA := time.Now() timeB := timeA.Round(0) fmt.Println(timeA) // 2018-10-26 16:43:03.799263739 +0800 CST m=+0.000357758 fmt.Println(timeB) // 2018-10-26 16:43:03.799263739 +0800 CST
到此這篇關(guān)于一文帶你理解Golang中的Time結(jié)構(gòu)的文章就介紹到這了,更多相關(guān)Go Time結(jié)構(gòu)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang?gorm錯(cuò)誤處理事務(wù)以及日志用法示例
這篇文章主要為大家介紹了golang?gorm錯(cuò)誤處理事務(wù)以及日志用法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04Win10系統(tǒng)下Golang環(huán)境搭建全過程
在編程語言的選取上,越來越多的人選擇了Golang,下面這篇文章主要給大家介紹了關(guān)于Win10系統(tǒng)下Golang環(huán)境搭建的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-01-01Go項(xiàng)目編寫Makefile規(guī)則文件概述
這篇文章主要為大家介紹了Go項(xiàng)目編寫Makefile文件規(guī)則概述,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04Golang教程之不可重入函數(shù)的實(shí)現(xiàn)方法
這篇文章主要給大家介紹了關(guān)于Golang教程之不可重入函數(shù)的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-09-09