本文最后更新于:2024年3月18日 凌晨
Go time
time 包提供了一些关于时间显示和测量用的函数。time 包中日历的计算采用的是公历,不考虑润秒。
时间类型
Go 语言中使用 time.Time
类型表示时间。我们可以通过 time.Now
函数获取当前的时间对象,然后从时间对象中可以获取到年、月、日、时、分、秒等信息。
1 2 3 4 5 6 7 8 9 10 11 12 13
| func timeDemo() { now := time.Now() fmt.Printf("current time:%v\n", now)
year := now.Year() month := now.Month() day := now.Day() hour := now.Hour() minute := now.Minute() second := now.Second() fmt.Println(year, month, day, hour, minute, second) }
|
Location 和 time zone
Go 语言中使用 location 来映射具体的时区。时区(Time Zone)是根据世界各国家与地区不同的经度而划分的时间定义,全球共分为 24 个时区。中国差不多跨 5 个时区,但为了使用方便只用东八时区的标准时即北京时间为准。
下面的示例代码中使用 beijing
来表示东八区 8 小时的偏移量,其中 time.FixedZone
和 time.LoadLocation
这两个函数则是用来获取 location 信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| func timezoneDemo() { secondsEastOfUTC := int((8 * time.Hour).Seconds()) beijing := time.FixedZone("Beijing Time", secondsEastOfUTC)
newYork, err := time.LoadLocation("America/New_York") if err != nil { fmt.Println("load America/New_York location failed", err) return } fmt.Println()
timeInUTC := time.Date(2009, 1, 1, 12, 0, 0, 0, time.UTC) sameTimeInBeijing := time.Date(2009, 1, 1, 20, 0, 0, 0, beijing) sameTimeInNewYork := time.Date(2009, 1, 1, 7, 0, 0, 0, newYork)
timesAreEqual := timeInUTC.Equal(sameTimeInBeijing) fmt.Println(timesAreEqual)
timesAreEqual = timeInUTC.Equal(sameTimeInNewYork) fmt.Println(timesAreEqual) }
|
在日常编码过程中使用时间对象的时候一定要注意其时区信息。
Unix Time
Unix Time 是自 1970 年 1 月 1 日 00:00:00 UTC 至当前时间经过的总秒数。下面的代码片段演示了如何基于时间对象获取到 Unix 时间。
1 2 3 4 5 6 7 8 9
| func timestampDemo() { now := time.Now() timestamp := now.Unix() milli := now.UnixMilli() micro := now.UnixMicro() nano := now.UnixNano() fmt.Println(timestamp, milli, micro, nano) }
|
time 包还提供了一系列将 int 64 类型的时间戳转换为时间对象的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| func timestamp2Time() { secondsEastOfUTC := int((8 * time.Hour).Seconds()) beijing := time.FixedZone("Beijing Time", secondsEastOfUTC)
t := time.Date(2022, 02, 22, 22, 22, 22, 22, beijing)
var ( sec = t.Unix() msec = t.UnixMilli() usec = t.UnixMicro() )
timeObj := time.Unix(sec, 22) fmt.Println(timeObj) timeObj = time.UnixMilli(msec) fmt.Println(timeObj) timeObj = time.UnixMicro(usec) fmt.Println(timeObj) }
|
时间间隔
time.Duration
是 time
包定义的一个类型,它代表两个时间点之间经过的时间,以纳秒为单位。time.Duration
表示一段时间间隔,可表示的最长时间段大约 290 年。
time 包中定义的时间间隔类型的常量如下:
1 2 3 4 5 6 7 8
| const ( Nanosecond Duration = 1 Microsecond = 1000 * Nanosecond Millisecond = 1000 * Microsecond Second = 1000 * Millisecond Minute = 60 * Second Hour = 60 * Minute )
|
例如:time.Duration
表示 1 纳秒,time.Second
表示 1 秒。
时间操作
Add
Go 语言的时间对象有提供 Add 方法如下。
1
| func (t Time) Add(d Duration) Time
|
例如,求一个小时之后的时间:
1 2 3 4 5
| func main() { now := time.Now() later := now.Add(time.Hour) fmt.Println(later) }
|
Sub
求两个时间之间的差值。
1
| func (t Time) Sub(u Time) Duration
|
- 返回一个时间段
t-u
。如果结果超出了 Duration 可以表示的最大值/最小值,将返回最大值/最小值。要获取时间点 t-d
(d 为 Duration),可以使用 t.Add(-d)
。
Equal
判断两个时间是否相同,会考虑时区的影响,因此不同时区标准的时间也可以正确比较。
1
| func (t Time) Equal(u Time) bool
|
- 本方法和用
t==u
不同,这种方法还会比较地点和时区信息。
Before
如果 t 代表的时间点在 u 之前,返回真;否则返回假。
1
| func (t Time) Before(u Time) bool
|
After
如果 t 代表的时间点在 u 之后,返回真;否则返回假。
1
| func (t Time) After(u Time) bool
|
定时器
使用 time.Tick(时间间隔)
来设置定时器,定时器的本质上是一个通道(channel)。
1 2 3 4 5 6
| func tickDemo() { ticker := time.Tick(time.Second) for i := range ticker { fmt.Println(i) } }
|
时间格式化
time.Format
函数能够将一个时间对象格式化输出为指定布局的文本表示形式,需要注意的是 Go 语言中时间格式化的布局不是常见的 YYYY-mm-dd H:M:S
,而是使用 2006-01-02 15:04:05.000
- 2006:年(Y)
- 01:月(m)
- 02:日(d)
- 15:时(H)
- 04:分(M)
- 05:秒(S)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| func formatDemo() { now := time.Now()
fmt.Println(now.Format("2006-01-02 15:04:05.000 Mon Jan")) fmt.Println(now.Format("2006-01-02 03:04:05.000 PM Mon Jan"))
fmt.Println(now.Format("2006/01/02 15:04:05.000")) fmt.Println(now.Format("2006/01/02 15:04:05.999"))
fmt.Println(now.Format("15:04:05")) fmt.Println(now.Format("2006.01.02")) }
|
- 如果想格式化为 12 小时格式,需在格式化布局中添加
PM
。
- 小数部分想保留指定位数就写 0,如果想省略末尾可能的 0 就写 9。
解析字符串格式的时间
对于从文本的时间表示中解析出时间对象,time
包中提供了 time.Parse
和 time.ParseInLocation
两个函数。
time.Parse
在解析时不需要额外指定时区信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| func parseDemo() { timeObj, err := time.Parse("2006/01/02 15:04:05", "2022/10/05 11:25:20") if err != nil { fmt.Println(err) return } fmt.Println(timeObj)
timeObj, err = time.Parse(time.RFC3339, "2022-10-05T11:25:20+08:00") if err != nil { fmt.Println(err) return } fmt.Println(timeObj) }
|
time.ParseInLocation
函数需要在解析时额外指定时区信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| func parseDemo() { now := time.Now() fmt.Println(now) loc, err := time.LoadLocation("Asia/Shanghai") if err != nil { fmt.Println(err) return } timeObj, err := time.ParseInLocation("2006/01/02 15:04:05", "2022/10/05 11:25:20", loc) if err != nil { fmt.Println (err) return } fmt.Println (timeObj) fmt.Println (timeObj.Sub (now)) }
|