go標準庫的學習-time

參考https://studygolang.com/pkgdocgolang

導入形式:數據庫

import "time"

time包提供了時間的顯示和測量用的函數。日曆的計算採用的是公曆。函數

 

1》時間點Timeoop

type Time

type Time struct {
    wall uint64
    ext  int64
    loc *Location
}

Time表明一個納秒精度的時間點。ui

Time零值表明時間點January 1, year 1, 00:00:00.000000000 UTC。由於本時間點通常不會出如今使用中,IsZero方法提供了檢驗時間是否顯式初始化的一個簡單途徑。spa

每個時間都具備一個地點信息(及對應地點的時區信息),當計算時間的表示格式時,如Format、Hour和Year等方法,都會考慮該信息。Local、UTC和In方法返回一個指定時區(但指向同一時間點)的Time。修改地點/時區信息只是會改變其表示;不會修改被表示的時間點,所以也不會影響其計算。.net

func (Time) String

func (t Time) String() string

String返回採用以下格式字符串的格式化時間。unix

"2006-01-02 15:04:05.999999999 -0700 MST"

 

const (
    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"
)

這些預約義的版式用於time.Format和time.Parse函數。用在版式中的參考時間是:code

Mon Jan 2 15:04:05 MST 2006

對應的Unix時間是1136239445orm

 

1)舉例如何使用在time.Format函數中:

func Now

func Now() Time

Now返回當前本地時間。

func (Time) Format

func (t Time) Format(layout string) string

Format根據layout指定的格式返回t表明的時間點的格式化文本表示,即將時間轉換成想要的格式,layout定義了參考時間

package main 
import(
    "fmt"
    "time"
)

func main() {
    fmt.Println(time.Now().Format(time.UnixDate))         //Tue Feb 12 12:10:21 CST 2019
    fmt.Println(time.Now().Format(time.RFC3339Nano))      //2019-02-12T12:10:21.880328+08:00
    fmt.Println(time.Now().Format(time.StampMicro))       //Feb 12 12:10:21.880337
    //自定義格式
    fmt.Println(time.Now().Format("2006-01-02 15:04:05")) //2019-02-12 12:10:21
    fmt.Println(time.Now().Format("Jan 2, 2006 at 3:04pm (MST)"))  //Feb 12, 2019 at 12:10pm (CST)
    fmt.Println(time.Now().Format("2006-Jan-02"))  //2019-Feb-12 
}

 

2)如何使用在time.Parse函數中,上面例子的逆向:

func Parse

func Parse(layout, value string) (Time, error)

Parse解析一個格式化的時間字符串並返回它表明的時間。layout定義了參考的時間格式

package main 
import(
    "fmt"
    "time"
)

func main() {
    unix, _ := time.Parse(time.UnixDate, "Tue Feb 12 12:10:21 CST 2019")
    fmt.Println(unix) //2019-02-12 12:10:21 +0800 CST

    rfc, _ := time.Parse(time.RFC3339Nano, "2019-02-12T12:10:21.880328+08:00")
    fmt.Println(rfc) //2019-02-12 12:10:21.880328 +0800 CST

    stamp, _ := time.Parse(time.StampMicro, "Feb 12 12:10:21.880337")
    fmt.Println(stamp) //0000-02-12 12:10:21.880337 +0000 UTC

    custom1Form := "2006-01-02 15:04:05"
    custom1, _ := time.Parse(custom1Form, "2019-02-12 12:10:21")
    fmt.Println(custom1) //2019-02-12 12:10:21 +0000 UTC

    custom2Form := "Jan 2, 2006 at 3:04pm (MST)"
    custom2, _ := time.Parse(custom2Form, "Feb 12, 2019 at 12:10pm (CST)")
    fmt.Println(custom2) //2019-02-12 12:10:00 +0800 CST

    custom3Form := "2006-Jan-02"
    custom3, _ := time.Parse(custom3Form, "2019-Feb-12")
    fmt.Println(custom3) //2019-02-12 00:00:00 +0000 UTC
}

數字表示的時區格式以下:

-0700  ±hhmm
-07:00 ±hh:mm

將格式字符串中的負號替換爲Z會觸發ISO 8601行爲(當時區是UTC時,輸出Z而不是時區偏移量),這樣:

Z0700  Z or ±hhmm
Z07:00 Z or ±hh:mm

 

其餘的獲取Time對象的方法:

首先先說明時區Location

type Location

type Location struct {
    name string
    zone []zone
    tx   []zoneTrans
    cacheStart int64
    cacheEnd   int64
    cacheZone  *zone
}

Location表明一個(關聯到某個時間點的)地點,以及該地點所在的時區。

 

var Local *Location = &localLoc

Local表明系統本地,對應本地時區,經過time.Local來使用。

 

var UTC *Location = &utcLoc

UTC表明通用協調時間,對應零時區,經過time.UTC來使用。

 

3)

func LoadLocation

func LoadLocation(name string) (*Location, error)

LoadLocation返回使用給定的名字建立的Location,即時區。

若是name是""或"UTC",返回UTC;若是name是"Local",返回Local;不然name應該是IANA時區數據庫裏有記錄的地點名(該數據庫記錄了地點和對應的時區),如"America/New_York"。

LoadLocation函數須要的時區數據庫可能不是全部系統都提供,特別是非Unix系統。此時LoadLocation會查找環境變量ZONEINFO指定目錄或解壓該變量指定的zip文件(若是有該環境變量);而後查找Unix系統的慣例時區數據安裝位置,最後查找$GOROOT/lib/time/zoneinfo.zip。

func (Time) In

func (t Time) In(loc *Location) Time

In返回採用loc指定的地點和時區,但指向同一時間點的Time。若是loc爲nil會panic。

package main 
import(
    "fmt"
    "time"
)

func main() {
    loc, _ := time.LoadLocation("America/Los_Angeles") //美國洛杉磯時區PST
    fmt.Println(loc) //America/Los_Angeles
    fmt.Println(time.Now()) //2019-02-12 15:03:12.649876 +0800 CST m=+0.000715568,相對於UTC時區正向差8小時
    fmt.Println(time.Now().In(loc)) //2019-02-11 23:03:12.649952 -0800 PST,相對於UTC時區正向差8小時,所以loc時區和本地時區相差16小時
}

 

4)

func ParseInLocation

func ParseInLocation(layout, value string, loc *Location) (Time, error)

ParseInLocation相似Parse但有兩個重要的不一樣之處。第一,當缺乏時區信息時,Parse將時間解釋爲UTC時間,而ParseInLocation將返回值的Location設置爲loc;第二,當時間字符串提供了時區偏移量信息時,Parse會嘗試去匹配本地時區,而ParseInLocation會去匹配loc。

舉例:

package main 
import(
    "fmt"
    "time"
)

func main() {
    loc, _ := time.LoadLocation("America/Los_Angeles")
    custom2Form := "2006-01-02 15:04:05"
    custom2, _ := time.ParseInLocation(custom2Form, "2019-02-12 12:10:21", loc)
    fmt.Println(custom2) //2019-02-12 12:10:21 -0800 PST,可見將時區設置爲了指定的loc時區
    custom2Parse, _ := time.Parse(custom2Form, "2019-02-12 12:10:21")
    fmt.Println(custom2Parse) //2019-02-12 12:10:21 +0000 UTC,可見若是沒有設置時區則默認爲UTC時區
}

 

5)

func Unix

func Unix(sec int64, nsec int64) Time

Unix建立一個本地時間,對應sec和nsec表示的Unix時間(從January 1, 1970 UTC至該時間的秒數和納秒數)。

nsec的值在[0, 999999999]範圍外是合法的。

 

得到時間的時間戳

func (Time) Unix

func (t Time) Unix() int64

Unix將t表示爲Unix時間,即從時間點January 1, 1970 UTC到時間點t所通過的時間(單位秒)。

func (Time) UnixNano

func (t Time) UnixNano() int64

UnixNano將t表示爲Unix時間,即從時間點January 1, 1970 UTC到時間點t所通過的時間(單位納秒)。若是納秒爲單位的unix時間超出了int64能表示的範圍,結果是未定義的。注意這就意味着Time零值調用UnixNano方法的話,結果是未定義的。

舉例:

package main 
import(
    "fmt"
    "time"
)

func main() {
    fmt.Println(time.Now().Unix())     //1549956211
    fmt.Println(time.Now().UnixNano()) //1549956211529784000
   fmt.Println(time.Unix(1549956211, 529784000)) //2019-02-12 15:23:31.529784 +0800 CST
}

而後使用上面例子獲得的秒數或納秒數來調用Unix獲得Time對象:

package main 
import(
    "fmt"
    "time"
)

func main() {
    fmt.Println(time.Unix(1549956211, 0)) //2019-02-12 15:23:31 +0800 CST
    fmt.Println(time.Unix(0, 1549956211529784000)) //2019-02-12 15:23:31.529784 +0800 CST
}

 

6)

func Date

func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time

Date返回一個時區爲loc、當地時間爲:

year-month-day hour:min:sec + nsec nanoseconds

的時間點。

month、day、hour、min、sec和nsec的值可能會超出它們的正常範圍,在轉換前函數會自動將之規範化。如October 32被修正爲November 1。

舉例:

package main 
import(
    "fmt"
    "time"
)

func main() {
    fmt.Println(time.Unix(1549956211, 529784000)) //2019-02-12 15:23:31.529784 +0800 CST
    //等價於上面的Unix方法
    t := time.Date(2019, time.February, 12, 15, 23, 31, 529784000, time.Local)
    fmt.Println(t)////2019-02-12 15:23:31.529784 +0800 CST
}

當你獲得了Time對象後,你就可以調用相應的函數來得到相應的信息,選擇其中幾個說明,其餘省略:

func (Time) Round

func (t Time) Round(d Duration) Time

返回距離t最近的時間點,獲得的是晚於t的時間,該時間點應該知足從Time零值到該時間點的時間段能整除d;若是有兩個知足要求的時間點,距離t相同,會向上舍入;若是d <= 0,會返回t的拷貝。

舉例:

package main 
import(
    "fmt"
    "time"
)

func main() {
    t := time.Date(2019, time.February, 12, 15, 23, 31, 529784000, time.Local)
    fmt.Println(t)////2019-02-12 15:23:31.529784 +0800 CST

    round := []time.Duration{
        time.Nanosecond,  //按納秒四捨五入,9位
        time.Microsecond, //按微秒,6位
        time.Millisecond, //按毫秒,3位,0省略
        time.Second,      //按秒
        2 * time.Second,  //按2秒
        time.Minute,      //按分
        10 * time.Minute, //按10分
        time.Hour,        //按小時
    }
    for _, d := range round {
        fmt.Printf("t.Round(%6s) = %s\n", d, t.Round(d).Format("15:04:05.999999999"))
    }
}

返回:

userdeMBP:go-learning user$ go run test.go
2019-02-12 15:23:31.529784 +0800 CST
t.Round(   1ns) = 15:23:31.529784
t.Round(   1µs) = 15:23:31.529784
t.Round(   1ms) = 15:23:31.53 //四捨五入爲530
t.Round(    1s) = 15:23:32 //四捨五入爲32
t.Round(    2s) = 15:23:32
t.Round(  1m0s) = 15:24:00
t.Round( 10m0s) = 15:20:00
t.Round(1h0m0s) = 15:00:00

 

func (Time) Truncate

func (t Time) Truncate(d Duration) Time

相似Round,可是返回的是最接近但早於t的時間點;若是d <= 0,會返回t的拷貝。

可見一樣的值使用Truncate獲得的結果和Round是不一樣的

舉例:

package main 
import(
    "fmt"
    "time"
)

func main() {
    t := time.Date(2019, time.February, 12, 15, 23, 31, 529784000, time.Local)
    fmt.Println(t)////2019-02-12 15:23:31.529784 +0800 CST

    round := []time.Duration{
        time.Nanosecond,  //按納秒四捨五入,9位
        time.Microsecond, //按微秒,6位
        time.Millisecond, //按毫秒,3位,0省略
        time.Second,      //按秒
        2 * time.Second,  //按2秒
        time.Minute,      //按分
        10 * time.Minute, //按10分
        time.Hour,        //按小時
    }
    for _, d := range round {
        fmt.Printf("t.Round(%6s) = %s\n", d, t.Truncate(d).Format("15:04:05.999999999"))
    }
}

返回:

userdeMBP:go-learning user$ go run test.go
2019-02-12 15:23:31.529784 +0800 CST
t.Round(   1ns) = 15:23:31.529784
t.Round(   1µs) = 15:23:31.529784
t.Round(   1ms) = 15:23:31.529
t.Round(    1s) = 15:23:31
t.Round(    2s) = 15:23:30
t.Round(  1m0s) = 15:23:00
t.Round( 10m0s) = 15:20:00
t.Round(1h0m0s) = 15:00:00

有關Duration的內容向下看

 

2》

type Weekday

type Weekday int

Weekday表明一週的某一天。

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

func (Weekday) String

func (d Weekday) String() string

String返回該日(周幾)的英文名("Sunday"、"Monday",……)

func (Time) Weekday

func (t Time) Weekday() Weekday

返回時間點t對應的那一週的周幾。

 

type Month

type Month int

Month表明一年的某個月。

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

func (Month) String

func (m Month) String() string

String返回月份的英文名("January","February",……)

舉例:

package main 
import(
    "fmt"
    "time"
)

func main() {
    fmt.Println(time.Now().Weekday()) //默認調用func (Weekday) String()函數,返回Tuesday
    fmt.Println(time.Now().Month()) //默認調用func (Month) String()函數,返回February
}

 

 

3》時間段Duration

type Duration

type Duration int64

Duration類型表明兩個時間點之間通過的時間,以納秒爲單位。可表示的最長時間段大約290年。

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

經常使用的時間段。沒有定義一天或超過一天的單元,以免夏時制的時區切換的混亂。

要將Duration類型值表示爲某時間單元的個數,用除法:

second := time.Second
fmt.Print(int64(second/time.Millisecond)) // prints 1000

要將整數個某時間單元表示爲Duration類型值,用乘法:

seconds := 10
fmt.Print(time.Duration(seconds)*time.Second) // prints 10s

func ParseDuration

func ParseDuration(s string) (Duration, error)

ParseDuration解析一個時間段字符串。一個時間段字符串是一個序列,每一個片斷包含可選的正負號、十進制數、可選的小數部分和單位後綴,如"300ms"、"-1.5h"、"2h45m"。合法的單位有"ns"、"us" /"µs"、"ms"、"s"、"m"、"h"。

舉例:

package main 
import(
    "fmt"
    "time"
)

func main() {
    dur1, _ := time.ParseDuration("1.5s")//1.5s
    dur2, _ := time.ParseDuration("2h45m") //2h45m0s
    dur3, _ := time.ParseDuration("-1.5h") //-1h30m0s
    fmt.Println(dur1)
    fmt.Println(dur2)
    fmt.Println(dur3)
}

func Since

func Since(t Time) Duration

Since返回從t到如今通過的時間,等價於time.Now().Sub(t)。

舉例:

package main 
import(
    "fmt"
    "time"
)

func main() {
    t := time.Date(2019, time.February, 12, 15, 23, 31, 529784000, time.Local)
    fmt.Println(t)//2019-02-12 15:23:31.529784 +0800 CST
    fmt.Println(time.Since(t))//50m31.878043s,如今據上面的時間已通過了50分鐘31秒
}

func (Duration) String

func (d Duration) String() string

返回時間段採用"72h3m0.5s"格式的字符串表示。最前面能夠有符號,數字+單位爲一個單元,開始部分的0值單元會被省略;若是時間段<1s,會使用"ms"、"us"、"ns"來保證第一個單元的數字不是0;若是時間段爲0,會返回"0"。

 

4》用於時間運算

來自https://blog.csdn.net/wschq/article/details/80114036

      // func Sleep(d Duration)   休眠多少時間,休眠時處於阻塞狀態,後續程序沒法執行
      time.Sleep(time.Duration(10) * time.Second)

      // func After(d Duration) <-chan Time  非阻塞,可用於延遲
      time.After(time.Duration(10) * time.Second)
      //select { case m := <-c: handle(m) case <-time.After(5 * time.Minute): fmt.Println("timed out") }
// 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與當前時間的間隔 // func (t Time) Add(d Duration) Time fmt.Println(dt.Add(time.Duration(10) * time.Second)) // func (t Time) Sub(u Time) Duration //// func (t Time) AddDate(years int, months int, days int) Time fmt.Println(dt.AddDate(1, 1, 1)) // func (t Time) Before(u Time) bool // func (t Time) After(u Time) bool // func (t Time) Equal(u Time) bool 比較時間點時儘可能使用Equal函數

 

5》定點計時

計時器(Timer)的原理和倒計時鬧鐘相似,都是給定多少時間後觸發。

打點器(Ticker)的原理和鐘錶相似,鐘錶每到整點就會觸發。

這兩種方法建立後會返回 time.Ticker 對象和 time.Timer 對象,裏面經過一個 C 成員,類型是隻能接收的時間通道(<-chan Time),使用這個通道就能夠得到時間觸發的通知。

1)type Timer

type Timer struct {
    C <-chan Time
    // 內含隱藏或非導出字段
}

Timer類型表明單次時間事件。當Timer到期時,當時的時間會被髮送給C,除非Timer是被AfterFunc函數建立的。

建立Timer的兩種方法:

1.func NewTimer

func NewTimer(d Duration) *Timer

NewTimer建立一個Timer,它會在最少過去時間段d後到期,向其自身的C字段發送當時的時間。

2.func AfterFunc

func AfterFunc(d Duration, f func()) *Timer

AfterFunc另起一個go程等待時間段d過去,而後調用f。它返回一個Timer,能夠經過調用其Stop方法來取消等待和對f的調用。

使用time.AfterFunc()實現等待一段時間後調用函數,並直到該函數生成的另外一goroutine結束後才結束main()函數的goroutine

package main 
import(
    "fmt" "time" ) func main() { //聲明一個用於退出的通道 exit := make(chan int) fmt.Println("start") //過1秒後,就會開一個新goroutine來運行匿名函數  time.AfterFunc(time.Second, func(){ //該匿名函數的做用就是在1秒後打印結果,並通知main()函數能夠結束主goroutine fmt.Println("one second after") exit <- 0 }) //main()正在等待從exit通道中接受數據來結束主goroutine <- exit }

返回:

userdeMBP:go-learning user$ go run test.go
start
one second after

 

⚠️以上兩函數均可以使用 Reset:

func (*Timer) Reset

func (t *Timer) Reset(d Duration) bool

Reset使t從新開始計時,(本方法返回後再)等待時間段d過去後到期。若是調用時t還在等待中會返回真;若是t已經到期或者被中止了會返回假。

這個有個須要注意的地方是使用 Reset 時須要確保 t.C 通道被釋放時才能調用,以防止發生資源競爭的問題,可經過如下方式解決:

      if !t.Stop() {//若是t已經被中止或者過時了,則先將 通道釋放,而後才調用Reset來從新計時,不然此時通道是滿的,致使資源競爭 <-t.C
      }
      t.Reset(d)t.C

func (*Timer) Stop

func (t *Timer) Stop() bool

Stop中止Timer的執行。若是還沒中止並中止了t會返回真;若是t已經被中止或者過時了會返回假。Stop不會關閉通道t.C,以免從該通道的讀取不正確的成功。

 

2)type Ticker

type Ticker struct {
    C <-chan Time // 週期性傳遞時間信息的通道
    // 內含隱藏或非導出字段
}

Ticker保管一個通道,並每隔一段時間向其傳遞"tick"。

func NewTicker

func NewTicker(d Duration) *Ticker

NewTicker返回一個新的Ticker,該Ticker包含一個通道字段,並會每隔時間段d就向該通道發送當時的時間。它會調整時間間隔或者丟棄tick信息以適應反應慢的接收者。若是d<=0會panic。關閉該Ticker能夠釋放相關資源。

 

舉例:

下面代碼建立一個打點器Ticker,每 500 毫秒觸發一塊兒;建立一個計時器Timer,2 秒後觸發,只觸發一次。

package main 
import(
    "fmt" "time" ) func main() { //建立一個打點器,每500毫秒觸發一次 ticker := time.NewTicker(time.Millisecond * 500) //建立一個計時器,2秒後觸發 timer := time.NewTimer(time.Second * 2) //聲明計數變量 var count int //不斷檢查通道狀況 for{ //多路複用通道 select{ case <- timer.C://計時器到時了,即2秒已到 fmt.Println("time is over,stop!!") goto StopLoop case <- ticker.C://打點器觸發了,說明已隔500毫秒 count++ fmt.Println("tick : ", count) } } //中止循環所到的標籤  StopLoop: fmt.Println("ending") } 

返回:

userdeMBP:go-learning user$ go run test.go
tick :  1 tick : 2 tick : 3 tick : 4 time is over,stop!! ending

 

func (*Ticker) Stop

func (t *Ticker) Stop()

Stop關閉一個Ticker。在關閉後,將不會發送更多的tick信息。Stop不會關閉通道t.C,以免從該通道的讀取不正確的成功。

相關文章
相關標籤/搜索