Go內(nèi)置的time
包提供了時間顯示和測量的函數(shù)
- 時間可分為時間點和時間段箱亿,為此Go提供了兩種基礎數(shù)據(jù)類型
time.Time
和time.Duration
。 - 所有與時間相關的業(yè)務都是基于時間點而衍生的惠爽,兩個時間點組成一個時間段。
- 時間包括時間值和時區(qū)瞬哼,沒有包含時區(qū)信息的時間是不完整的婚肆、有歧義的。
- 日歷的計算采用的是公歷
- Go提供針對某些特定業(yè)務提供了諸如
go.Location
時區(qū)倒槐、go.Timer
定時器...
功能 | 描述 |
---|---|
time.Time | 時間點 |
time.Duration | 時間段 |
time.Location | 時區(qū) |
time.Timer | 定時器 |
time.Ticker | 周期觸發(fā)定時的計時器 |
time.C | 存放時間點的管道 |
時間類型
time
包提供了一個數(shù)據(jù)類型time.Time
用來表示時間旬痹,時間一般包含時間值和時區(qū)兩部分,時間值是一個納秒精度的時間點讨越。
package time
type Time struct {
wall uint64
ext int64
loc *Location
}
time.Time
結構包含三個字段:
字段 | 類型 | 描述 |
---|---|---|
wall | uint64 | 墻上時鐘两残,表示距離公元1年1月1日00:00:00UTC的秒數(shù)。 |
ext | int64 | 時間模式把跨,表示納秒人弓。 |
loc | *time.Location | 時區(qū),處理偏移量着逐。不同時區(qū)對應的時間也不同崔赌。 |
最準確的時間計算是使用“原子振蕩周期”所計算的物理時鐘(Atomic Clock,原子鐘)耸别,又被定義為標準時間(International Atomic Time)健芭。常用的UTC(Universal Time Coordinated,世界協(xié)調(diào)時間)就是利用原子鐘為基準定義出來的秀姐,UTC標準時間以GMT(Greenwich Mean Time慈迈,格林威治時間)這個時區(qū)為基準。
本地時間 = UTC + 時區(qū)差
北京時間 = UTF + 8個小時
操作系統(tǒng)中存在兩個不同的時鐘省有,分別是單調(diào)時鐘(monotonic time)痒留、墻上時鐘(wall time/real time)
- 單調(diào)時鐘是本機硬件的節(jié)拍數(shù),不同機器沒有可比性蠢沿。由于石英鐘本身的誤差伸头,時間會有閏秒等原因,因此單調(diào)時鐘與墻上時鐘是不一致的舷蟀。
- 墻上時鐘又稱為時鐘時間恤磷,是進程運行的時鐘總量,其值與系統(tǒng)中同時運行的進程數(shù)量有關野宜。進程從開始運行到結束碗殷,時鐘走過的時間,包括進程在阻塞和等待狀態(tài)的時間速缨。
墻上時鐘 | 大小 |
---|---|
flag | 1位 |
時間戳 | 33位 |
納秒 | 30位 |
時間模式分為:是否包含單調(diào)時鐘锌妻、外部輸入的時間
- 若時間模式
ext
包含單調(diào)時鐘,則wall
字段中會存在一個時間戳秒代表墻上時鐘和一個時間戳納秒代表墻上時鐘旬牲。 - 若時間模式
ext
不包含單調(diào)時鐘仿粹,則wall
字段中會包含一個時間戳納秒代表墻上時鐘,ext
字段則包含一個時間戳秒代表墻上時鐘原茅。
當前時間
-
time.Now()
會返回當前本地時間對象
func Now() Time
例如:獲取當前本地時間信息
t := time.Now()
fmt.Println(t) // 2021-12-28 13:10:36.5987998 +0800 CST m=+0.003958401
從時間對象中獲取時間分量信息
時間分量 | 描述 |
---|---|
t.Year() | 年 |
t.Month() | 月 |
t.Day() | 日 |
t.Hour() | 小時數(shù) |
t.Minute() | 分鐘 |
t.Second() | 秒數(shù) |
t.Nanosecond() | 納秒吭历,1毫秒 = 1000納秒, 1秒 = 1000毫秒 |
t.Weekday() | 星期幾 |
t.YearDay() | 一年中的第n天 |
t.Zone() | 獲取時區(qū) |
t := time.Now()
fmt.Println(t) // 2021-12-28 13:43:30.9266336 +0800 CST m=+0.004069101
fmt.Printf("Year = %d\n", t.Year()) // 2021
fmt.Printf("Month = %d\n", t.Month()) // 12
fmt.Printf("Day = %d\n", t.Day()) // 28
fmt.Printf("Hour = %d\n", t.Hour()) // 13
fmt.Printf("Minute = %d\n", t.Minute()) // 43
fmt.Printf("Second = %d\n", t.Second()) // 30
fmt.Printf("NanoSecond = %d\n", t.Nanosecond()) // 926633600
fmt.Printf("Weekday = %d\n", t.Weekday()) // 2
fmt.Printf("YearDay = %d\n", t.YearDay()) // 362
fmt.Println(t.Zone()) // CST 28800
時間解析
time.Parse()
會將字符串類型的日期時間轉換為UTC標準的Time類型
package time
func Parse(layout, value string) (Time, error)
例如:將字符串"2021-01-04 12:00:00"轉換為標準UTC的time.Time
類型
t, err := time.Parse("2006-01-02 15:04:05", "2021-01-04 12:00:00")
if err != nil {
panic(err)
}
fmt.Printf("%T\n", t) // time.Time
fmt.Printf("%+v\n", t) // 2021-01-04 12:00:00 +0000 UTC
時間戳
UNIX時間戳(UNIX Timestamp)
- Unix時間又稱為POSIX時間擂橘,是UNIX或類UNIX操作系統(tǒng)使用的時間表示方式晌区。
- Unix時間表示從UTC的1970年1月1日0時0分0秒開始到現(xiàn)在的總秒數(shù),不考慮閏秒。
func (t Time) Unix() int64
func (t Time) UnixNano() int64
時間戳 | 單位 | 長度 |
---|---|---|
t.Unix() | 秒 | 10位 |
t.UnixNano() | 納秒 | 19位 |
s := t.Unix()
ns := t.UnixNano()
ms := t.UnixNano() / 1e6
fmt.Printf("timestamp = %d, unixnano = %d, ms = %d\n", s, ns, ms)
timestamp = 1618738171, unixnano = 1618738171513428200, ms = 1618738171513
19位納秒轉13位毫秒
ms := t.UnixNano() / 1e6
fmt.Println(ms) // 1618737494948
-
time.Unix()
函數(shù)可將時間戳轉換為時間點對象
func time.Unix(sec int64, nsec int64) time.Time
時間格式
time.Format()
用于獲取時間并格式化為字符串朗若,格式化占位符2006-01-02 15:04:05
表示GoLang誕生時間恼五,此處為固定寫法。
func (t Time) Format(layout string) string
例如:將時間點對象轉換為指定格式的字符串
t := time.Now()
fmt.Println(t)//2021-04-18 17:53:23.8149167 +0800 CST m=+0.002995001
str := t.Format("2006-01-02 15:04:05")
fmt.Println(str)//2021-04-18 17:53:23
例如:將時間戳轉換為指定格式的字符串
ts := time.Now().Unix()
fmt.Println(ts)//1618739719
str := time.Unix(ts,0).Format("2006-01-02 15:04:05")
fmt.Println(str)//2021-04-18 17:55:19
標準時間
- UTC(Coordinated Universal Time哭懈,協(xié)調(diào)世界時)是最主要的世界時間標準灾馒,它以原子時秒長為基礎,在時刻上盡量接近于格林尼治標準時間(Greenwich Mean Time遣总,GMT)睬罗。
- UTC是世界上調(diào)節(jié)時鐘和時間的主要時間標準,它與0度經(jīng)線的平太陽時相差不超過1秒旭斥,且不遵守夏令時容达。
- UTC是最接近格林威治標準時間(GMT)的替代時間系統(tǒng)之一,對于大多數(shù)用途來說垂券,UTC時間被認為與GMT時間互換花盐,但GMT時間已不再被科學界所確定。
func (t Time) UTC() Time
例如:將GMT格林威治時間轉換為UTC時間
t := time.Now()
fmt.Println(t)//2021-04-18 17:57:51.7228428 +0800 CST m=+0.002020201
utc := t.UTC()
fmt.Println(utc)//2021-04-18 09:57:51.7228428 +0000 UTC
時區(qū)
時間其實包括時間值和時區(qū)圆米,沒有時區(qū)信息的時間是不完整的卒暂。使用沒有時區(qū)的非標準時間表示格式是有隱患的,由于解析時會根據(jù)使用場景的默認設置娄帖,如系統(tǒng)時區(qū)也祠、數(shù)據(jù)庫默認時區(qū)等,可能會引發(fā)事故近速。因此需確保服務器系統(tǒng)诈嘿、數(shù)據(jù)庫、應用程序時間統(tǒng)一的時區(qū)削葱。
time
包存在兩個時區(qū)變量分別是time.UTC
即UTC時間奖亚、time.Local
本地時間
time.Location()
函數(shù)返回時間點對象的地點和時區(qū)信息
func (t Time) Location() *Location
例如:獲取時間點對應的時區(qū)
t := time.Now()
loc := t.Location()
fmt.Println(loc)//Local
time.LoadLocation()
用于獲取給定名字創(chuàng)建的時區(qū)
func time.LoadLocation(name string) (*time.Location, error)
例如:獲取服務器所在時區(qū)
loc,err := time.LoadLocation("Asia/Shanghai")
if err!=nil {
println(err)
}
println(loc)//0xc0000c2000
是否能夠拿到時區(qū)取決于機器本地的zoneinfo
文件,time.LoadLocation()
函數(shù)將會返回一個*time.Location
指針對象析砸。
計時器
time.Ticker
time.Ticker
是一個周期觸發(fā)定時的計時器昔字,一旦被定義每隔一段時間會自動觸發(fā)。
type Ticker struct {
C <-chan Time // 周期性傳遞時間信息的通道
r runtimeTimer
}
time.Ticker
會按照一個指定的時間間隔重復的向通道C
發(fā)送系統(tǒng)當前時間值首繁,通道的接收者可以按固定的時間間隔從通道中讀取事件作郭。
//實現(xiàn)原理
go func(t *time.Ticker){
for{
select{
case <-t.C:
fmt.Printf("ticker: run\n")
}
}
}(ticker)
在goroutine
周期性執(zhí)行一些事務時非常有用,比如狀態(tài)狀態(tài)日志弦疮、輸出夹攒、計算等。
例如:
ticker := time.NewTicker(time.Second * 3)
defer ticker.Stop()
fmt.Println(time.Now().Format("2006-01-02 15:04:05"))
time.Sleep(time.Second * 4)
for{
select{
case <-ticker.C:
fmt.Println(time.Now())
}
}
time.NewTicker
NewTicker
方法用于返回一個新的Ticker胁塞,Ticker中包含一個通道字段C
會每隔時間段d
就向該通道發(fā)送當前的時間咏尝。
func time.NewTicker(d time.Duration) *time.Ticker
- 時間間隔
d
的單位為納秒(ns, int64)压语,在工廠函數(shù)time.NewTicker
中以time.Duration
類型的參數(shù)傳入。 -
*Ticker
指向定時器的指針
例如:定時執(zhí)行编检,循環(huán)執(zhí)行不退出胎食。
//創(chuàng)建計時器,每隔1秒后定時器會向channel發(fā)送一個事件蒙谓,包含當前時間斥季。
ticker := time.NewTicker(time.Second * 1)
i:=0
for{
//執(zhí)行若干次后退出
if i>5 {
break
}
i++
fmt.Println(time.Now().Format("2006-01-02 15:04:05"))
//從打點器中獲取通道
<-ticker.C
}
//清理計時器
ticker.Stop()
例如:
//創(chuàng)建計時器训桶,每隔1秒后定時器會向channel發(fā)送一個事件累驮,包含當前時間。
ticker := time.NewTicker(time.Second * 1)
i:=0
for{
//執(zhí)行若干次后退出
if i>5 {
//清理計時器
ticker.Stop()
//跳出循環(huán)
break
}
//從打點器中獲取通道
select{
case <-ticker.C:
i++
fmt.Println(time.Now().Format("2006-01-02 15:04:05"))
}
}
例如:
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for{
select{
case t := <-ticker.C:
fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second())
}
}
time.Tick
time.Tick()
返回的是一個通道舵揭,每隔指定時間就會有數(shù)據(jù)從通道中出來谤专。
func Tick(d Duration) <-chan Time {
if d <= 0 {
return nil
}
return NewTicker(d).C
}
實現(xiàn)固定時間重復執(zhí)行,即定期循環(huán)午绳。
for{
time.Sleep(time.Second * 2)
fmt.Println(time.Now())
}
更優(yōu)雅的方案
-
range
是可以不接收遍歷的值的置侍,若不接收則可簡寫。
for range time.Tick(time.Second * 2){
fmt.Println(time.Now())
}
ticker.Stop
func (t *Ticker) Stop() {
stopTimer(&t.r)
}
-
ticker.Stop()
方法會關閉一個Ticker
拦焚,關閉后將不會再發(fā)送更多的tick信息蜡坊。 -
ticker.Stop()
方法不會關閉通道t.C
,只能避免從通道的讀取不正確的成功赎败。
ticker.Reset
func (t *Ticker) Reset(d Duration) {
if t.r.f == nil {
panic("time: Reset called on uninitialized Ticker")
}
modTimer(&t.r, when(d), int64(d), t.r.f, t.r.arg, t.r.seq)
}
時間段
time.Duration
-
time.Duration
是time
包定義的一個類型秕衙,表示一段時間間隔。 -
Duration
類型表示兩個時間點之間經(jīng)過的時間段僵刮,以納秒為單位据忘,可表示的最長時間段大約290年。 -
Duration
時間段實際上是int64
類型搞糕,單位納秒勇吊。
實際編程中不會直接賦值時間段為一個數(shù)字,而是會采用time
包提供的常量窍仰。
const (
Nanosecond Duration = 1
Microsecond = 1000 * Nanosecond
Millisecond = 1000 * Microsecond
Second = 1000 * Millisecond
Minute = 60 * Second
Hour = 60 * Minute
)
時間運算
Add
- 獲取時間點增加時間段后的時間點
func (t Time) Add(d Duration) Time
例如:計算1天后的時間點
t1 := time.Now()
fmt.Println(t1)//2021-04-18 18:27:30.482194 +0800 CST m=+0.002020201
t2 := t1.Add(time.Hour * 24)
fmt.Println(t2)//2021-04-19 18:27:30.482194 +0800 CST m=+86400.002020201
例如:計算1天前的時間點
t2 := t1.Add(-time.Hour * 24)
fmt.Println(t2)//2021-04-17 18:30:48.1375322 +0800 CST m=-86399.998035299
Sub
- 計算兩個事件之間的差值
func (t Time) Sub(u Time) Duration
例如:
t1 := time.Now()
fmt.Println(t1)//2021-04-18 18:27:30.482194 +0800 CST m=+0.002020201
t2 := t1.Add(time.Hour * 24)
fmt.Println(t2)//2021-04-17 18:30:48.1375322 +0800 CST m=-86399.998035299
d := t2.Sub(t1)
fmt.Println(d)//24h0m0s
時間比較
Equal
func (t Time) Equal(u Time) bool
- 判斷兩個時間點
t
和u
是否相同汉规,會考慮時區(qū)的影響。
例如:
t1 := time.Now()
fmt.Println(t1)//2021-04-18 18:27:30.482194 +0800 CST m=+0.002020201
t2 := t1.Add(time.Hour * 24)
fmt.Println(t2)//2021-04-17 18:30:48.1375322 +0800 CST m=-86399.998035299
flag := t2.Equal(t1)
fmt.Println(flag)//false
Before
func (t Time) Before(u Time) bool
- 判斷時間點
t
是否在指定時間點u
之前
After
func (t Time) After(u Time) bool
- 判斷某時間點
t
是否在指定時間點u
之后