程序開發中,時間操做是不可避免的,在這裏記錄一下Go中常見的操做。bash
Go
中的時間最底層的數據結構爲Duration
, 在Duration
的基礎上,咱們定義了下面的概念:數據結構
const (
Nanosecond Duration = 1 // 納秒,計算Duration的是使用ns
Microsecond = 1000 * Nanosecond 微秒,計算Duration的是使用us
Millisecond = 1000 * Microsecond 毫秒, 計算Duration的是使用ms
Second = 1000 * Millisecond 秒,計算Duration的是使用s
Minute = 60 * Second 分,計算Duration的是使用m
Hour = 60 * Minute 時,計算Duration的是使用h
)
複製代碼
那麼Duration
能夠如何操做呢?函數
seconds := 10
time.Duration(seconds)*time.Second // 返回Duration結構
複製代碼
ParseDutation
主要用於解析字符串,使用字符串的能夠避免使用time.Duration
不方便表示的時間段。hours, _ := time.ParseDuration("10h") // 生成10個小時的duration
complex, _ := time.ParseDuration("1h10m10s") // 生成1小時10分鐘10秒的duration
micro, _ := time.ParseDuration("1µs") // 生成1微妙的duration
複製代碼
如何計算兩個時間的時間差,返回Duration
結構?注意ui
start := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)
end := time.Date(2000, 1, 1, 12, 0, 0, 0, time.UTC)
difference := end.Sub(start)
fmt.Printf("difference = %v\n", difference)
複製代碼
time.Since
等價於time.Now().Sub(t)
,用於計算當前時間和以前某個時間的時間差。spa
time.Until
等價於t.Sub(time.Now())
,用於計算以後的某個時間和當前時間的時間差。code
那麼Duration
究竟是什麼數據結構呢?Duration
只是int64
的一種暱稱,在此之上也實現多種方法,如.Hours()
,.Minutes()
,.Seconds()
等。orm
type Duration int64
複製代碼
通常狀況不須要設置Location
,若是要設置location
,可以在哪些地方使用呢? 首先是在time.Date
構造time.Time
的過程當中,最後一個參數設置當前時間所在時區。對象
Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location)
複製代碼
那麼time.Location
如何初始化呢?使用time.LoadLocation
來加載開發
location, err := time.LoadLocation("America/Los_Angeles")
timeInUTC := time.Date(2018, 8, 30, 12, 0, 0, 0, time.UTC) // time.UTC是*Location結構
複製代碼
帶時區的時間轉化,字符串
t := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC) // 當前時間爲UTC時間
fmt.Printf("Go launched at %s\n", t.Local()) // t.Local轉化本地時間, 2009-11-11 07:00:00 +0800 CST。
複製代碼
東八區怎麼表示呢?
// 方法一
l,_ := time.LoadLocation("Asia/Shanghai")
// 方法二,可能用的很少,定義一個名字,而後自行計算時區+-12 * 3600
var cstZone = time.FixedZone("CST", 8*3600) // 東八
fmt.Println(time.Now().In(cstZone).Format("01-02-2006 15:04:05"))
複製代碼
爲何是乘3600呢?從秒開始計算,下面兩行獲得北京時區。
secondsEastOfUTC := int((8 * time.Hour).Seconds())
beijing := time.FixedZone("Beijing Time", secondsEastOfUTC)
複製代碼
type Ticker struct {
C <-chan Time // channel 每隔固定的時間會發送消息
}
複製代碼
每隔固定的時間會發送信號,這個固定時間怎麼獲取呢?經過NewTicker接收Duration對象獲取,下面代碼演示了每一個1秒打印,打印10秒的功能。
ticker := time.NewTicker(time.Second)
defer ticker.Stop() // 【重要】關閉ticker
done := make(chan bool)
go func() {
time.Sleep(10 * time.Second)
done <- true
}()
for {
select {
case <-done:
fmt.Println("Done!")
return
case t := <-ticker.C:
fmt.Println("Current time: ", t)
}
}
複製代碼
Time
是操縱時間的核心對象。
time.Parse(layout, string) // 獲取指定字符串表明的時間
time.ParseInLocation(layout, value string, loc *Location) // 帶上時區的時間
複製代碼
今天開發中遇到一個問題,計算兩個時間相差多少秒?
todayEnd, _ := time.Parse(timeLayout, fmt.Sprintf("%s %s", time.Now().Format("2006-01-02"), "23:59:59"))
todayStart := time.Now()
validSeds := todayEnd.Sub(todayStart).Minutes()
fmt.Println("validSeds: ", int(validSeds))
複製代碼
上面的代碼計算時間一直不正確,就是由於time.Parse
獲取出來的時間是相對0時區的,而time.Now
使用的是本地時區,須要將其中Parse
出的代碼修爲下面形式:
l, _ := time.LoadLocation("Asia/Shanghai")
todayEnd, _ := time.ParseInLocation(timeLayout, fmt.Sprintf("%s %s", time.Now().Format("2006-01-02"), "23:59:59"), l)
複製代碼
計算當前的時間戳
time.Unix() // 秒級 time.UnixNano() // 毫秒級
增長一個Duration
。
play
start := time.Date(2009, 1, 1, 0, 0, 0, 0, time.UTC)
oneDayLater := start.AddDate(0, 0, 1) // 增長一天
oneMonthLater := start.AddDate(0, 1, 0) // 增長一月
oneYearLater := start.AddDate(1, 0, 0) // 增長一年
複製代碼
不過AddDate
均可以使用Add
+Duraion
組合解決。
比較兩個時間的前後
year2000 := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)
year3000 := time.Date(3000, 1, 1, 0, 0, 0, 0, time.UTC)
isYear3000AfterYear2000 := year3000.After(year2000) // True
isYear2000AfterYear3000 := year2000.After(year3000) // False
isYear3000BeforeYear2000 := year3000.Before(year2000) // false
isYear2000BeforeYear3000 := year2000.Before(year3000) // true
複製代碼
func (t Time) Clock() (hour, min, sec int) // 返回t的時分秒
func (t Time) Date() (year int, month Month, day int) // 返回t的年月日
複製代碼
t.Format 時間格式化顯示
t.In 經過複製的方式,改變當前時間的時區
func (t Time) In(loc *Location) Time
複製代碼
聲明time.Time
未賦值,改值爲January 1, year 1, 00:00:00 UTC.
分別使用本地時區生成時間, 0時區生成時間。
返回當前時區的名稱和偏移0時區多少秒
t := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.Local)
name, offset := t.Zone()
fmt.Println(name, offset) // CST 28800(8*3600)
複製代碼
Timer
是個什麼東西?最基本仍是個channel
type Timer struct {
C <-chan Time // 時間到了,發送信號,作好接收準備
}
複製代碼
怎麼初始化Timer
呢?
func NewTimer(d Duration) *Timer
複製代碼
時間到了,要執行什麼函數呢?
func AfterFunc(d Duration, f func()) *Timer 複製代碼
中途若是想着stop
定時器,怎麼辦?
func (t *Timer) Stop() bool 複製代碼
爲了確保關閉?
if !t.Stop() {
<-t.C
}
複製代碼
兩個封裝的方式相同,使用暱稱的方式掛載更多的方法,是變量可以存在更多的可能性。
// Month
type Month int
const (
January Month = 1 + iota
February
March
April
May
June
July
August
September
October
November
December
)
func (m Month) String() string{}
// Weekday
type Weekday int
const (
Sunday Weekday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
)
func (d Weekday) String() string 複製代碼