參考https://studygolang.com/pkgdoc
導入形式:
import "time"
time包提供了時間的顯示和測量用的函數。日歷的計算采用的是公歷。
1》時間點Time
type Time
type Time struct { wall uint64 ext int64 loc *Location }
Time代表一個納秒精度的時間點。
Time零值代表時間點January 1, year 1, 00:00:00.000000000 UTC。因為本時間點一般不會出現在使用中,IsZero方法提供了檢驗時間是否顯式初始化的一個簡單途徑。
每一個時間都具有一個地點信息(及對應地點的時區信息),當計算時間的表示格式時,如Format、Hour和Year等方法,都會考慮該信息。Local、UTC和In方法返回一個指定時區(但指向同一時間點)的Time。修改地點/時區信息只是會改變其表示;不會修改被表示的時間點,因此也不會影響其計算。
func (Time) String
func (t Time) String() string
String返回采用如下格式字符串的格式化時間。
"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函數。用在版式中的參考時間是:
Mon Jan 2 15:04:05 MST 2006
對應的Unix時間是1136239445
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已經被停止或者過期了,則先將t.C
通道釋放,然后才調用Reset來重新計時,否則此時通道是滿的,導致資源競爭 <-t.C
}
t.Reset(d)
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,以避免從該通道的讀取不正確的成功。