时间可分为时间点与时间段,golang 也不例外,提供了以下两种基础类型

  • 时间点(Time)
  • 时间段(Duration)

除此之外 golang 也提供了以下类型,做一些特定的业务

  • 时区(Location)
  • Ticker
  • Timer(定时器)

我们将按以上顺序来介绍 time 包的使用。

1 时间点(Time)

go 针对不同的参数类型提供了以下初始化的方式

  1. $ cat time0.go
  2. package main
  3. import (
  4. "fmt"
  5. "time"
  6. )
  7. func main() {
  8. fmt.Println(time.Now())
  9. fmt.Println(time.Now().Local())
  10. fmt.Println(time.Now().Local().Hour())
  11. }
  12. 输出结果
  13. $ go run golang-time.go
  14. 2020-12-30 23:20:44.008514 +0800 CST m=+0.000139949
  15. 2020-12-30 23:20:44.008811 +0800 CST
  16. 23
  1. $ cat time1.go
  2. package main
  3. import (
  4. "fmt"
  5. "time"
  6. )
  7. func main() {
  8. // func Now() Time
  9. fmt.Println(time.Now())
  10. // func Parse(layout, value string) (Time, error)
  11. fmt.Println(time.Parse("2016-01-02 15:04:05", "2020-12-30 18:22:00"))
  12. // func ParseInLocation(layout, value string, loc *Location) (Time, error) (layout已带时区时可直接用Parse)
  13. fmt.Println(time.ParseInLocation("2006-01-02 15:04:05", "2020-12-12 15:09:09", time.Local))
  14. // func Unix(sec int64, nsec int64) Time
  15. fmt.Println(time.Unix(1e9, 0))
  16. // func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time
  17. fmt.Println(time.Date(2018, 1, 3, 15, 30, 10, 0, time.Local))
  18. // func (t Time) In(loc *Location) Time 当前时间对应指定时区的时间
  19. loc, _ := time.LoadLocation("America/Los_Angeles")
  20. fmt.Println(time.Now().In(loc))
  21. }
  22. $ go run golang-time.go
  23. 2020-12-30 23:22:30.977714 +0800 CST m=+0.000096359
  24. 0001-01-01 00:00:00 +0000 UTC parsing time "2020-12-30 18:22:00": month out of range
  25. 2020-12-12 15:09:09 +0800 CST <nil>
  26. 2001-09-09 09:46:40 +0800 CST
  27. 2018-01-03 15:30:10 +0800 CST
  28. 2020-12-30 07:22:30.977961 -0800 PST

2 格式化

  1. to string

格式化为字符串我们需要使用 time.Format 方法来转换成我们想要的格式

  1. fmt.Println(time.Now().Format("2006-01-02 15:04:05")) // 2020-12-30 23:22:30
  2. fmt.Println(time.Now().Format(time.UnixDate)) // Wed Dec 30 23:25:46 CST 2020

复制代码Format 函数中可以指定你想使用的格式,同时 time 包中也给了一些我们常用的格式

  1. const (
  2. ANSIC = "Mon Jan _2 15:04:05 2006"
  3. UnixDate = "Mon Jan _2 15:04:05 MST 2006"
  4. RubyDate = "Mon Jan 02 15:04:05 -0700 2006"
  5. RFC822 = "02 Jan 06 15:04 MST"
  6. RFC822Z = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
  7. RFC850 = "Monday, 02-Jan-06 15:04:05 MST"
  8. RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
  9. RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
  10. RFC3339 = "2006-01-02T15:04:05Z07:00"
  11. RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
  12. Kitchen = "3:04PM"
  13. // Handy time stamps.
  14. Stamp = "Jan _2 15:04:05"
  15. StampMilli = "Jan _2 15:04:05.000"
  16. StampMicro = "Jan _2 15:04:05.000000"
  17. StampNano = "Jan _2 15:04:05.000000000"
  18. )

注意: galang 中指定的特定时间格式为 "2006-01-02 15:04:05 -0700 MST", 为了记忆方便,按照美式时间格式 月日时分秒年 外加时区 排列起来依次是 01/02 03:04:05PM ‘06 -0700,刚开始使用时需要注意。

3 to time stamp

方法

  1. func (t Time) Unix() int64
  2. func (t Time) UnixNano() int64
  1. $ cat time2.go
  2. package main
  3. import (
  4. "fmt"
  5. "time"
  6. )
  7. func main() {
  8. fmt.Println(time.Now().Unix())
  9. // 获取指定日期的时间戳
  10. dt, _ := time.Parse("2016-01-02 15:04:05", "2020-12-30 12:24:51")
  11. fmt.Println(dt.Unix())
  12. fmt.Println(time.Date(2020, 12, 30, 15, 30, 10, 0, time.Local).Unix())
  13. }
  14. $ go run time2.go
  15. 1609342320
  16. -62135596800
  17. 1609313410

4 其他

time 包还提供了一些常用的方法

  1. func (t Time) Date() (year int, month Month, day int)
  2. func (t Time) Clock() (hour, min, sec int)
  3. func (t Time) Year() int
  4. func (t Time) Month() Month
  5. func (t Time) Day() int
  6. func (t Time) Hour() int
  7. func (t Time) Minute() int
  8. func (t Time) Second() int
  9. func (t Time) Nanosecond() int
  10. func (t Time) YearDay() int
  11. func (t Time) Weekday() Weekday
  12. func (t Time) ISOWeek() (year, week int)
  13. func (t Time) IsZero() bool
  14. func (t Time) Local() Time
  15. func (t Time) Location() *Location
  16. func (t Time) Zone() (name string, offset int)
  17. func (t Time) Unix() int64

5 时间段(Duartion)

介绍完了时间点,我们再来介绍时间段,即 Duartion 类型, 我们业务也是很常用的类型。

  1. func (d Duration) Hours() float64
  2. func (d Duration) Minutes() float64
  3. func (d Duration) Seconds() float64
  4. func (d Duration) Nanoseconds() int64
  5. func (d Duration) Round(m Duration) Duration // 四舍五入
  6. func (d Duration) Truncate(m Duration) Duration // 向下取整
  1. $ cat time3.go
  2. package main
  3. import (
  4. "fmt"
  5. "time"
  6. )
  7. func main() {
  8. tp, _ := time.ParseDuration("1.5s")
  9. fmt.Println(tp.Truncate(1000), tp.Round(100), tp.Seconds(), tp.Nanoseconds())
  10. }
  11. $ go run golang-time.go
  12. 1.5s 1.5s 1.5 1500000000

6 时区(Location)

  1. $ cat time4.go
  2. package main
  3. import (
  4. "fmt"
  5. "time"
  6. )
  7. func main() {
  8. loc1, err := time.LoadLocation("")
  9. if err != nil {
  10. fmt.Print("time location error")
  11. }
  12. fmt.Println(time.Date(2020, 12, 30, 12, 0, 0, 0, loc1))
  13. loc2, err := time.LoadLocation("Local")
  14. fmt.Println(time.Date(2020, 12, 30, 12, 0, 0, 0, loc2))
  15. local, _ := time.LoadLocation("America/Los_Angeles")
  16. fmt.Println(time.Date(2020, 12, 30, 12, 0, 0, 0, local))
  17. }
  18. $ go run golang-time.go
  19. 2020-12-30 12:00:00 +0000 UTC
  20. 2020-12-30 12:00:00 +0800 CST
  21. 2020-12-30 12:00:00 -0800 PST

7 时间运算

语法:

  1. //通过字符串,默认UTC时区初始化Time
  2. func Parse(layout, value string) (Time, error)
  3. //通过字符串,指定时区来初始化Time
  4. func ParseInLocation(layout, value string, loc *Location) (Time, error)
  5. //通过unix 标准时间初始化Time
  6. func Unix(sec int64, nsec int64) Time
  1. $ cat time5.go
  2. package main
  3. import (
  4. "fmt"
  5. "strings"
  6. "time"
  7. )
  8. func main() {
  9. now := time.Now()
  10. m, _ := time.ParseDuration("-1m")
  11. m1 := now.Add(m)
  12. fmt.Println(m1)
  13. // 8个小时前
  14. h, _ := time.ParseDuration("-1h")
  15. h1 := now.Add(8 * h)
  16. fmt.Println(h1)
  17. // 一天前
  18. d, _ := time.ParseDuration("-24h")
  19. d1 := now.Add(d)
  20. fmt.Println(d1)
  21. printSplit(50)
  22. // 10分钟后
  23. mm, _ := time.ParseDuration("1m")
  24. mm1 := now.Add(mm)
  25. fmt.Println(mm1)
  26. // 8小时后
  27. hh, _ := time.ParseDuration("1h")
  28. hh1 := now.Add(hh)
  29. fmt.Println(hh1)
  30. // 一天后
  31. dd, _ := time.ParseDuration("24h")
  32. dd1 := now.Add(dd)
  33. fmt.Println(dd1)
  34. printSplit(50)
  35. // Sub 计算两个时间差
  36. subM := now.Sub(m1)
  37. fmt.Println(subM.Minutes(), "分钟")
  38. sumH := now.Sub(h1)
  39. fmt.Println(sumH.Hours(), "小时")
  40. sumD := now.Sub(d1)
  41. fmt.Printf("%v 天\n", sumD.Hours()/24)
  42. }
  43. func printSplit(count int) {
  44. fmt.Println(strings.Repeat("#", count))
  45. }

输出:

  1. $ go run golang-time.go
  2. 2020-12-30 23:39:34.743924 +0800 CST m=-59.999920355
  3. 2020-12-30 15:40:34.743924 +0800 CST m=-28799.999920355
  4. 2020-12-29 23:40:34.743924 +0800 CST m=-86399.999920355
  5. ##################################################
  6. 2020-12-30 23:50:34.743924 +0800 CST m=+600.000079645
  7. 2020-12-31 00:40:34.743924 +0800 CST m=+3600.000079645
  8. 2020-12-31 23:40:34.743924 +0800 CST m=+86400.000079645
  9. ##################################################
  10. 1 分钟
  11. 8 小时
  12. 1
  1. $ cat time6.go
  2. package main
  3. import (
  4. "fmt"
  5. "time"
  6. )
  7. func main() {
  8. dt1 := time.Date(2020, 12, 30, 12, 40, 30, 30, time.Local)
  9. dt2 := time.Date(2020, 11, 30, 12, 40, 30, 30, time.Local)
  10. // 不用关注时区,go会转换成时间戳进行计算
  11. fmt.Println(dt1.Sub(dt2))
  12. }
  13. $ go run golang-time.go
  14. 720h0m0s
  1. $ cat time7.go
  2. package main
  3. import (
  4. "fmt"
  5. "time"
  6. )
  7. func main() {
  8. local, _ := time.LoadLocation("America/Los_Angeles")
  9. timeFormat := "2006-01-02 15:04:05"
  10. //func Unix(sec int64, nsec int64) Time {
  11. time1 := time.Unix(1680390585, 0) //通过unix标准时间的秒,纳秒设置时间
  12. time2, _ := time.ParseInLocation(timeFormat, "2020-12-30 19:36:25", local) //洛杉矶时间
  13. fmt.Println(time1.In(local).Format(timeFormat))
  14. fmt.Println(time2.In(local).Format(timeFormat))
  15. chinaLocal, _ := time.LoadLocation("Local") //运行时,该服务器必须设置为中国时区,否则最好是采用"Asia/Chongqing"之类具体的参数。
  16. fmt.Println(time2.In(chinaLocal).Format(timeFormat))
  17. }
  18. $ go run golang-time.go
  19. 2023-04-01 16:09:45
  20. 2020-12-30 19:36:25
  21. 2020-12-31 11:36:25

8 比较两个时间点

  1. $ cat time8.go
  2. package main
  3. import (
  4. "fmt"
  5. "time"
  6. )
  7. func main() {
  8. dt := time.Date(2020, 12, 30, 12, 34, 45, 100, time.Local)
  9. fmt.Println(time.Now().After(dt)) // true
  10. fmt.Println(time.Now().Before(dt)) // false
  11. // 是否相等 判断两个时间点是否相等时推荐使用 Equal 函数
  12. fmt.Println(dt.Equal(time.Now()))
  13. }
  14. $ go run golang-time.go
  15. true
  16. false
  17. false

9 Ticker类型

Ticker 类型包含一个 channel,有时我们会遇到每隔一段时间执行的业务(比如设置心跳时间等),就可以用它来处理,这是一个重复的过程。

  1. $ cat time9.go
  2. package main
  3. import (
  4. "fmt"
  5. "time"
  6. )
  7. func main() {
  8. d := time.Duration(time.Second*2)
  9. t := time.NewTicker(d)
  10. defer t.Stop()
  11. for {
  12. <- t.C
  13. fmt.Println("timeout...")
  14. }
  15. }
  16. [root@localhost time]# go run time9.go
  17. timeout...
  18. timeout...
  19. timeout...
  20. timeout...

10 Timer类型

Timer 类型用来代表一个单独的事件,当设置的时间过期后,发送当前的时间到 channel, 我们可以通过以下两种方式来创建

  1. func AfterFunc(d Duration, f func()) *Timer // 指定一段时间后指定的函数
  2. func NewTimer(d Duration) *Timer

以上两函数都可以使用 Reset, 这个有个需要注意的地方是使用 Reset 时需要确保 t.C 通道被释放时才能调用,以防止发生资源竞争的问题,可通过以下方式解决

  1. if !t.Stop() {
  2. <-t.C
  3. }
  4. t.Reset(d)

  1. cat time10.go
  2. package main
  3. import (
  4. "fmt"
  5. "time"
  6. )
  7. func main() {
  8. d := time.Duration(time.Second*2)
  9. t := time.NewTimer(d)
  10. defer t.Stop()
  11. for {
  12. <- t.C
  13. fmt.Println("timeout...")
  14. // need reset
  15. t.Reset(time.Second*2)
  16. }
  17. }
  18. [root@localhost time]# go run time10.go
  19. timeout...
  20. timeout...

11 总结

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. func main() {
  7. //time.Time代表一个纳秒精度的时间点
  8. var t time.Time
  9. //返回当前时间:2020-12-30 23:48:37.311332 +0800 CST m=+0.000068759
  10. t = time.Now()
  11. fmt.Printf("%v\n", t)
  12. //返回所在时区:Local
  13. fmt.Printf("%v\n", t.Location())
  14. //返回UTC时间和UTC时区:2020-12-30 15:48:37.311332 +0000 UTC UTC
  15. fmt.Printf("%v %v\n", t.UTC(), t.UTC().Location())
  16. //同上,In()返回指定时区的时间:2020-12-30 15:48:37.311332 +0000 UTC UTC
  17. fmt.Printf("%v %v\n", t.In(time.UTC), t.In(time.UTC).Location())
  18. //返回当地时区的时间:2020-12-30 23:48:37.311332 +0800 CST Local
  19. fmt.Printf("%v %v\n", t.Local(), t.Local().Location())
  20. //根据时间戳返回本地时间,参数分别表示秒数和纳秒数
  21. //2023-06-26 19:46:50 +0800 CST
  22. t2 := time.Unix(1687780010, 0)
  23. fmt.Println(t2)
  24. //根据指定时间返回time.Time,分别指定年,月,日,时,分,秒,纳秒,时区
  25. //2020-05-26 15:30:20 +0800 CST
  26. t3 := time.Date(2020, time.Month(5), 26, 15, 30, 20, 0, t.Location())
  27. fmt.Println(t3)
  28. //格式化输出时间:2020-12-30 23:49:51
  29. t4 := time.Now()
  30. fmt.Println(t4.Format("2006-01-02 15:04:05"))
  31. //获取时间信息:2020-12-30 23:49:51
  32. t5 := time.Now()
  33. //返回日期:2020 December 30
  34. fmt.Println(t5.Date())
  35. //返回年:2020
  36. fmt.Println(t5.Year())
  37. //返回月:December
  38. fmt.Println(t5.Month())
  39. //返回日:30
  40. fmt.Println(t5.Day())
  41. //返回星期:Wednesday
  42. fmt.Println(t5.Weekday())
  43. //返回ISO 9601标准下的年份和星期编号:2020 53
  44. fmt.Println(t5.ISOWeek())
  45. //返回时分秒:23 49 51
  46. fmt.Println(t5.Clock())
  47. //返回小时:23
  48. fmt.Println(t5.Hour())
  49. //返回分钟:49
  50. fmt.Println(t5.Minute())
  51. //返回秒:51
  52. fmt.Println(t5.Second())
  53. //返回纳秒:222602000
  54. fmt.Println(t5.Nanosecond())
  55. //返回一年中对应的天:365
  56. fmt.Println(t5.YearDay())
  57. //返回时区的规范名,时区相对于UTC的时间偏移量(秒):CST 28800
  58. fmt.Println(t5.Zone())
  59. //返回时间戳:1609343391
  60. fmt.Println(t5.Unix())
  61. //返回纳秒时间戳:1609343391222602000
  62. fmt.Println(t5.UnixNano())
  63. //时间的比较与计算
  64. t6 := time.Now()
  65. //是否零时时间:false
  66. fmt.Println(t6.IsZero())
  67. //t6时间在t5时间之后,返回真:true
  68. fmt.Println(t6.After(t5))
  69. //t5时间在t6时间之前,返回真:true
  70. fmt.Println(t5.Before(t6))
  71. //时间是否相同:true
  72. fmt.Println(t6.Equal(t6))
  73. //返回t6加上纳秒的时间:2020-12-30 23:49:51.222631 +0800 CST m=+0.000295290
  74. fmt.Println(t6.Add(10000))
  75. //返回两个时间之差的纳秒数:18.768µs
  76. fmt.Println(t6.Sub(t5))
  77. //返回t6加1年,1月,1天的时间:2022-01-31 23:49:51.222621 +0800 CST
  78. fmt.Println(t6.AddDate(1, 1, 1))
  79. //时间的序列化
  80. t7 := time.Now()
  81. //序列化二进制
  82. bin, _ := t7.MarshalBinary()
  83. //反序列化二进制:2020-12-30 23:49:51.222631 +0800 CST
  84. t7.UnmarshalBinary(bin)
  85. fmt.Println(t7)
  86. //序列化json:"2020-12-30T23:49:51.222631+08:00"
  87. json, _ := t7.MarshalJSON()
  88. fmt.Println(string(json))
  89. //反序列化json:2020-12-30 23:49:51.222631 +0800 CST
  90. t7.UnmarshalJSON(json)
  91. fmt.Println(t7)
  92. //序列化文本:2020-12-30T23:49:51.222631+08:00
  93. txt, _ := t7.MarshalText()
  94. fmt.Println(string(txt))
  95. //反序列化文本:2020-12-30 23:49:51.222631 +0800 CST
  96. t7.UnmarshalText(txt)
  97. fmt.Println(t7)
  98. //gob编码:2020-12-30 23:49:51.222631 +0800 CST
  99. gob, _ := t7.GobEncode()
  100. t7.GobDecode(gob)
  101. fmt.Println(t7)
  102. //时间段time.Duration
  103. dur := time.Duration(6666666600000)
  104. //返回字符串表示:1h51m6.6666s
  105. fmt.Println(dur.String())
  106. //返回小时表示:1.8518518333333334
  107. fmt.Println(dur.Hours())
  108. //返回分钟表示:111.11111
  109. fmt.Println(dur.Minutes())
  110. //返回秒表示:6666.6666
  111. fmt.Println(dur.Seconds())
  112. //返回纳秒表示:6666666600000
  113. fmt.Println(dur.Nanoseconds())
  114. //时区time.Location,返回时区名:local
  115. fmt.Println(time.Local.String())
  116. //通过地点名和时间偏移量返回时区:Shanghai
  117. fmt.Println(time.FixedZone("Shanghai", 800))
  118. //通过给定时区名称,返回时区:Asia/Shanghai
  119. loc, _ := time.LoadLocation("Asia/Shanghai")
  120. fmt.Println(loc)
  121. //阻塞当前进程3秒
  122. time.Sleep(time.Second * 3)
  123. //定时器time.Timer,创建一个1秒后触发定时器
  124. timer1 := time.NewTimer(time.Second * 1)
  125. <-timer1.C
  126. fmt.Println("timer1 end")
  127. //1秒后运行函数
  128. time.AfterFunc(time.Second*1, func() {
  129. fmt.Println("wait 1 second")
  130. })
  131. time.Sleep(time.Second * 3)
  132. //打点器time.Ticker,创建一个打点器,在固定1秒内重复执行
  133. ticker := time.NewTicker(time.Second)
  134. num := 1
  135. for {
  136. if num > 5 {
  137. ticker.Stop()
  138. break
  139. }
  140. select {
  141. case <-ticker.C:
  142. num++
  143. fmt.Println("1 second...")
  144. }
  145. }
  146. }

12 实用场景

  1. t := 5
  2. time.Sleep(time.Second * 5) // ok 正常
  3. time.Sleep(time.Second * t) // error 出现标题错误提示
  4. time.Sleep(time.Second * time.Duration(t)) // ok 应该这样转

13 时间的格式化和解析

  1. package main
  2. import "fmt"
  3. import "time"
  4. func main() {
  5. p := fmt.Println
  6. // 这里是一个基本的按照 RFC3339 进行格式化的例子,使用
  7. // 对应模式常量。
  8. t := time.Now()
  9. p(t.Format(time.RFC3339))
  10. // 时间解析使用同 `Format` 相同的形式值。
  11. t1, e := time.Parse(
  12. time.RFC3339,
  13. "2012-11-01T22:08:41+00:00")
  14. p(t1)
  15. // `Format` 和 `Parse` 使用基于例子的形式来决定日期格式,
  16. // 一般你只要使用 `time` 包中提供的模式常量就行了,但是你
  17. // 也可以实现自定义模式。模式必须使用时间 `Mon Jan 2 15:04:05 MST 2006`
  18. // 来指定给定时间/字符串的格式化/解析方式。时间一定要按照
  19. // 如下所示:2006为年,15 为小时,Monday 代表星期几,等等。
  20. p(t.Format("3:04PM"))
  21. p(t.Format("Mon Jan _2 15:04:05 2006"))
  22. p(t.Format("2006-01-02T15:04:05.999999-07:00"))
  23. form := "3 04 PM"
  24. t2, e := time.Parse(form, "8 41 PM")
  25. p(t2)
  26. // 对于纯数字表示的时间,你也可以使用标准的格式化字
  27. // 符串来提出出时间值得组成。
  28. fmt.Printf("%d-%02d-%02dT%02d:%02d:%02d-00:00\n",
  29. t.Year(), t.Month(), t.Day(),
  30. t.Hour(), t.Minute(), t.Second())
  31. // `Parse` 函数在输入的时间格式不正确是会返回一个
  32. // 错误。
  33. ansic := "Mon Jan _2 15:04:05 2006"
  34. _, e = time.Parse(ansic, "8:41PM")
  35. p(e)
  36. }

输出结果:

  1. 2020-11-23T11:06:33+08:00
  2. 2012-11-01 22:08:41 +0000 +0000
  3. 11:06AM
  4. Mon Nov 23 11:06:33 2020
  5. 2020-11-23T11:06:33.251533+08:00
  6. 0000-01-01 20:41:00 +0000 UTC
  7. 2020-11-23T11:06:33-00:00
  8. parsing time "8:41PM" as "Mon Jan _2 15:04:05 2006": cannot parse "8:41PM" as "Mon"

参考连接:
https://juejin.im/post/5ae32a8651882567105f7dd3
http://static.markbest.site/blog/92.html
Time 类型详解
https://blog.csdn.net/xixihahalelehehe/article/details/104540727?ops_request_misc=%25257B%252522request%25255Fid%252522%25253A%252522160932314316780288745853%252522%25252C%252522scm%252522%25253A%25252220140713.130102334.pc%25255Fblog.%252522%25257D&request_id=160932314316780288745853&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v1~rank_blog_v1-1-104540727.pc_v1_rank_blog_v1&utm_term=time