『Go 內(nèi)置庫(kù)第一季:time』

This_is_Fine_Gopher.png

大家好,我叫謝偉,是一名程序員。

近期會(huì)更新內(nèi)置庫(kù)的學(xué)習(xí)筆記,主要參考文獻(xiàn)來自于官方文檔和源代碼。

本節(jié)的主題:time

時(shí)間的操作在項(xiàng)目中使用的非常頻繁,比如說數(shù)據(jù)庫(kù)中,經(jīng)常有時(shí)間的操作,比如根據(jù)時(shí)間進(jìn)行劃分,統(tǒng)計(jì)之類的功能。

那么如何學(xué)會(huì)常用的操作呢?

大綱:

  • 自己總結(jié)的常用操作
  • 官方的 API
  • 學(xué)習(xí)總結(jié)

自己總結(jié)的常用操作

時(shí)間類型的數(shù)據(jù),我們?cè)陧?xiàng)目中都會(huì)進(jìn)行哪些操作呢?

要在思維里掌握時(shí)間類型的數(shù)據(jù)的操作,又應(yīng)該如何梳理呢?

1. 時(shí)間的單位

暫時(shí)撇開代碼層面,日常生活中關(guān)于時(shí)間的單位都有哪些呢?

  • 時(shí)
  • 毫秒

一般到毫秒層面就夠了,當(dāng)然還可以繼續(xù)劃分:微秒、納秒...

那時(shí)間的單位的轉(zhuǎn)換是如何進(jìn)行的呢?

  • 1 y = 12 m
  • 1 m = 4 w
  • 1 w = 7 d
  • 1 d = 24 h
  • 1 h = 60 min
  • 1 min = 60 s
  • 1 s = 1000 ms
  • 1 ms = 1000 us
  • 1 us = 1000 ns

為什么要了解這些啊? 這不是常識(shí)嗎?是的。經(jīng)常有常識(shí)性的問題,轉(zhuǎn)換成代碼層面而出錯(cuò)。所以有必要進(jìn)行了回顧。

2. 時(shí)間操作

了解了時(shí)間的基本單位,那就好辦了。

func main(){
    now := time.Now()

    fmt.Println(now.Year())
    fmt.Println(now.Month())
    fmt.Println(now.Day())
    fmt.Println(now.Hour())
    fmt.Println(now.Minute())
    fmt.Println(now.Second())
    fmt.Println(now.Date())

}
>>
2018-11-13 22:30:03.500763 +0800 CST m=+0.000810351
2018
November
13
22
30
3
2018 November 13

所有這些時(shí)間的單位底層都是 int 類型。既然是 int 類型,那 November 是如何得到的?

很簡(jiǎn)單,底層定義這樣一個(gè)關(guān)于月份的數(shù)組,將對(duì)應(yīng)的位置的值返回即可。


var months = [...]string{
    "January",
    "February",
    "March",
    "April",
    "May",
    "June",
    "July",
    "August",
    "September",
    "October",
    "November",
    "December",
}

3. 時(shí)間戳

  • 時(shí)間戳的使用也非常廣泛,比如為了表示唯一性
  • 時(shí)間戳的概念:1970年01月01日00時(shí)00分00秒(北京時(shí)間1970年01月01日08時(shí)00分00秒)起至現(xiàn)在的總秒數(shù)

時(shí)間戳,這個(gè)概念,如果不是程序員,可能完成沒有必要了解,有更好的閱讀時(shí)間的顯示方式,沒必要知道這么一串?dāng)?shù)字。

在 Go 中,如何將時(shí)間轉(zhuǎn)換成時(shí)間戳?

func main(){
    now := time.Now()
    
    fmt.Println(now.UnixNano())
    fmt.Println(now.Unix())
}
>>
1542119403501037000
1542119403

上文一個(gè)轉(zhuǎn)換為納秒,一個(gè)是轉(zhuǎn)換為秒??梢钥吹睫D(zhuǎn)換單位是 10^9

那如何將時(shí)間戳轉(zhuǎn)換為 時(shí)間類型?


func main(){

    fmt.Println(time.Unix(1542119403, 1542119403000000000))
    
    fmt.Println(time.Unix(1542119403, 1542119403000000000).UTC())

}

>>
2067-09-26 13:00:06 +0800 CST
2067-09-26 05:00:06 +0000 UTC

關(guān)于時(shí)間,還存在一個(gè)重要的概念,即:時(shí)區(qū)

  • UTC 校準(zhǔn)的全球時(shí)間
  • CST China Standard Time UT 8:00

所以經(jīng)常會(huì)出現(xiàn)時(shí)間相差 8 小時(shí)的情況,比如,本地程序運(yùn)行正常,推送到倉(cāng)庫(kù)中,自動(dòng)構(gòu)建夠,程序得不到預(yù)期的值,有可能是因?yàn)榉?wù)器的時(shí)間的時(shí)區(qū)和本地的不一致。

4. 時(shí)間和字符串的相互轉(zhuǎn)化

涉及時(shí)間的顯示的布局有個(gè)默認(rèn)值:2006-01-02 15:04:05

這個(gè)時(shí)間的速記:123456

func main(){
    
    now := time.Now()
    fmt.Println(now.Format("2006-01-02 15:04:05"))
}

    timeString := "2019-01-02 15:03:00"

    fmt.Println(time.Parse("2006-01-02 15:04:05", timeString))
    fmt.Println(time.ParseInLocation("2006-01-02 15:04:05", timeString, time.Local))

>>
2018-11-13 22:59:08
2019-01-02 15:03:00 +0000 UTC <nil>
2019-01-02 15:03:00 +0800 CST <nil>

還記得之前字符串和基本數(shù)據(jù)類型(整型、浮點(diǎn)型、布爾型)相互轉(zhuǎn)化的章節(jié)。

我們總結(jié):

  • 基本數(shù)據(jù)類型轉(zhuǎn)化為字符串:帶關(guān)鍵字 Format, 且沒有錯(cuò)誤返回
  • 字符串轉(zhuǎn)化為基本數(shù)據(jù)類型:帶關(guān)鍵字 Parse , 且存在錯(cuò)誤返回

時(shí)間類型和字符串之間的轉(zhuǎn)化和上文的總結(jié)一致。

啟發(fā):使用關(guān)鍵字:Format 、 Parse 對(duì)自己函數(shù)進(jìn)行命名組織;沒有錯(cuò)誤類型的函數(shù)不返回錯(cuò)誤類型

有時(shí)候我們可能只需要時(shí)間的部分值,比如說,只需要整點(diǎn)的值,那關(guān)于這些操作,又應(yīng)該如何操作呢?


func main(){
    timeToString()
}

var timeToString = func() {

    now := time.Now()

    fmt.Println(now.Format("2006-01-02 15:00:00"))
    fmt.Println(now.Format("2006-01-02 15:04:00"))
    fmt.Println(now.Format("2006-01-02 00:00:00"))

    fmt.Println(now.Round(time.Hour))
    fmt.Println(now.Round(time.Minute))
    fmt.Println(now.Round(time.Second))
    fmt.Println(now.Truncate(time.Hour))
    fmt.Println(now.Truncate(time.Minute))
    fmt.Println(now.Truncate(time.Second))

}
>>
2018-11-13 23:00:00
2018-11-13 23:12:00
2018-11-13 00:00:00
2018-11-13 23:00:00 +0800 CST
2018-11-13 23:13:00 +0800 CST
2018-11-13 23:12:34 +0800 CST
2018-11-13 23:00:00 +0800 CST
2018-11-13 23:12:00 +0800 CST
2018-11-13 23:12:33 +0800 CST

可以看出,存在兩種方法,一種是操作 布局,即更改那個(gè)默認(rèn)值 2006-01-02 15:04:05; 一種是使用內(nèi)置的 Round, Truncate 兩種的區(qū)別是Round 向上取整,Truncate 向下取整

5. 兩個(gè)時(shí)間之間的操作

上面的例子絕大多數(shù)是單個(gè)時(shí)間的操作,比如取時(shí)間戳、時(shí)間和字符串之間轉(zhuǎn)化、獲取時(shí)間的年月日等。

日常操作中,兩個(gè)時(shí)間的操作也是比較頻繁的。

比如:

  • 判斷一個(gè)時(shí)間是否是在該時(shí)間之前、之后
  • 給出給定時(shí)間的某個(gè)時(shí)間節(jié)點(diǎn)的值:比如 1小時(shí)前、1天前、1年前、1年后、1天后、1小時(shí)后等
func main(){
    timeOp()

}

var timeOp = func() {
    now := time.Now()

    fmt.Println(now.Add(1 * time.Hour))
    fmt.Println(now.Add(24 * time.Hour))
    fmt.Println(now.Add(-10 * time.Hour))
}

>>
2018-11-14 00:21:47.48055 +0800 CST m=+3600.000854277
2018-11-14 23:21:47.48055 +0800 CST m=+86400.000854277
2018-11-13 13:21:47.48055 +0800 CST m=-35999.999145723

得到 1小時(shí)后、1天后、10小時(shí)前

好,那這些時(shí)間前后都有哪些值可以選擇?


const (
    Nanosecond  Duration = 1
    Microsecond          = 1000 * Nanosecond
    Millisecond          = 1000 * Microsecond
    Second               = 1000 * Millisecond
    Minute               = 60 * Second
    Hour                 = 60 * Minute
)

這些常量,輔以恰當(dāng)?shù)倪\(yùn)算。

那 1年前咋搞?還運(yùn)算嗎?傻瓜。


func main(){
    timeOpDate()
}

var timeOpDate = func() {
    now := time.Now()

    fmt.Println(now.AddDate(-1, 0, 0))
    fmt.Println(now.AddDate(2, 0, 0))
    fmt.Println(now.AddDate(0, 1, 0))
}
>>
2017-11-13 23:26:18.697797 +0800 CST
2020-11-13 23:26:18.697797 +0800 CST
2018-12-13 23:26:18.697797 +0800 CST

完成啦。

基本上這兩個(gè)函數(shù)就可以完成目的。

那如何計(jì)算兩個(gè)時(shí)間之間的差呢?


func main(){
    timeInterval()
}

var timeInterval = func() {
    now := time.Now()
    stringTime := "2018-11-14 20:00:00"

    newTime, _ := time.ParseInLocation("2006-01-02 15:04:05", stringTime, time.Local)

    if newTime.After(now) {
        subTime := newTime.Sub(now)
        fmt.Println("newTime after now")
        fmt.Println(subTime.Hours())
        fmt.Println(subTime.Minutes())
        fmt.Println(subTime.Seconds())
        fmt.Println(subTime.Nanoseconds())
    }
    if newTime.Before(now) {
        subTime := now.Sub(newTime)
        fmt.Println(subTime.String())
    }
}
>>
newTime after now
20.463746377777777
1227.8247826666666
73669.48696
73669486960000

6. 其他

  • 得出時(shí)間是本周的周幾
  • 得出時(shí)間是該年的第幾周
func main(){
    fmt.Println(time.Now().ISOWeek())
    fmt.Println(time.Now().Weekday())
}
>>
2018 46
Tuesday

官方API

大概我們沒講有這些內(nèi)容:

  • 定時(shí)器?
  • 底層是如何獲取時(shí)間的?
  • 序列化和反序列化(還記得 json 那節(jié) Marshler 嗎)
func (t Time) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.Marshaler interface. The time is a quoted string in RFC 3339 format, with sub-second precision added if present.

自定義了序列化的結(jié)構(gòu)

總結(jié)

枚舉類型在 Go 里面的時(shí)候,用來表示連續(xù)的遞增的值。

比如想表示顏色、比如像表示星期幾

這種連續(xù)的值,一般都選擇枚舉類型來定義。

const (
    Sunday Weekday = iota
    Monday
    Tuesday
    Wednesday
    Thursday
    Friday
    Saturday
)

const (
    January Month = 1 + iota
    February
    March
    April
    May
    June
    July
    August
    September
    October
    November
    December
)

比如想自定義的顏色順序:

const (
    Red = iota
    Orange
    Yellow
    Green
    Cyan
    Blue
    Purple
)

func main(){
        fmt.Println(Red,
        Orange,
        Yellow,
        Green,
        Cyan,
        Blue,
        Purple)
}

>>
0 1 2 3 4 5 6

當(dāng)然提到枚舉,考點(diǎn)不會(huì)這樣考你,而是如下面的操作:

const (
    Red = iota
    Orange
    Yellow = iota + 10
    Green = iota
    Cyan
    Blue = 10
    Purple
)


問你各個(gè)值得多少?


0 1 12 3 4 10 10

<完>

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 國(guó)家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說閱讀 12,513評(píng)論 6 13
  • 第5章 引用類型(返回首頁(yè)) 本章內(nèi)容 使用對(duì)象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類型 使用基本類型...
    大學(xué)一百閱讀 3,691評(píng)論 0 4
  • 1 Object 對(duì)象 教程:https://wangdoc.com/javascript/stdlib/obje...
    智勇雙全的小六閱讀 2,513評(píng)論 0 0
  • 結(jié)束了10天的新加坡泰國(guó)之旅,有太多太多想說的了,本打算每天都寫旅行日記,但是太累了,特別是前三天暴走新加坡。然后...
    吃橙啊啊啊閱讀 134評(píng)論 0 0
  • 一、小括號(hào),圓括號(hào)() 1、單小括號(hào) () ①命令組。括號(hào)中的命令將會(huì)新開一個(gè)子shell順序執(zhí)行,所以括號(hào)中的變...
    北山學(xué)者閱讀 1,598評(píng)論 0 2

友情鏈接更多精彩內(nèi)容