time标准库
时间和日期是编程里常用的,`time`包提供了时间的显示和测量用的函数
# 时间类型
time.Time
类型表示时间,我们可以通过timme.Now
函数获取当前的时间对象,然后可以获取对象的年月日时分秒等信息。
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)
}
2
3
4
5
6
7
8
9
10
11
12
# Location 和 time zone
每个Time
都有一个相关联的Location
用来表示时间,时区(Time Zone)是世界根据各个国家与不同地区的精度而划分的时间定义。我国使用东八区的标准时间即北京时间为准。
// timezoneDemo 时区示例
func timezoneDemo() {
// 中国没有夏令时,使用一个固定的8小时的UTC时差。
// 对于很多其他国家需要考虑夏令时。
secondsEastOfUTC := int((8 * time.Hour).Seconds())
// FixedZone 返回始终使用给定区域名称和偏移量(UTC 以东秒)的 Location。
beijing := time.FixedZone("Beijing Time", secondsEastOfUTC)
// 如果当前系统有时区数据库,则可以加载一个位置得到对应的时区
// 例如,加载纽约所在的时区
newYork, err := time.LoadLocation("America/New_York") // UTC-05:00
if err != nil {
fmt.Println("load America/New_York location failed", err)
return
}
fmt.Println()
// 加载上海所在的时区
//shanghai, err := time.LoadLocation("Asia/Shanghai") // UTC+08:00
// 加载东京所在的时区
//tokyo, err := time.LoadLocation("Asia/Tokyo") // UTC+09:00
// 创建时间对象需要指定位置。常用的位置是 time.Local(当地时间) 和 time.UTC(UTC时间)。
//timeInLocal := time.Date(2009, 1, 1, 20, 0, 0, 0, time.Local) // 系统本地时间
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)
// 北京时间(东八区)比UTC早8小时,所以上面两个时间看似差了8小时,但表示的是同一个时间
timesAreEqual := timeInUTC.Equal(sameTimeInBeijing)
fmt.Println(timesAreEqual)
// 纽约(西五区)比UTC晚5小时,所以上面两个时间看似差了5小时,但表示的是同一个时间
timesAreEqual = timeInUTC.Equal(sameTimeInNewYork)
fmt.Println(timesAreEqual)
}
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
# Unix Time
时间戳是基于 1970 年 1 月 1 日 00:00:00 UTC 至当前时间经过的总秒数
// timestampDemo 时间戳
func timestampDemo() {
now := time.Now() // 获取当前时间
timestamp := now.Unix() // 秒级时间戳
milli := now.UnixMilli() // 毫秒时间戳 Go1.17+
micro := now.UnixMicro() // 微秒时间戳 Go1.17+
nano := now.UnixNano() // 纳秒时间戳
fmt.Println(timestamp, milli, micro, nano)
}
2
3
4
5
6
7
8
9
10
将
int64
类型的时间戳转换为时间对象的方法
// timestamp2Time 将时间戳转为时间对象
func timestamp2Time() {
// 获取北京时间所在的东八区时区对象
secondsEastOfUTC := int((8 * time.Hour).Seconds())
beijing := time.FixedZone("Beijing Time", secondsEastOfUTC)
// 北京时间 2022-02-22 22:22:22.000000022 +0800 CST
t := time.Date(2022, 02, 22, 22, 22, 22, 22, beijing)
var (
sec = t.Unix()
msec = t.UnixMilli()
usec = t.UnixMicro()
)
// 将秒级时间戳转为时间对象(第二个参数为不足1秒的纳秒数)
timeObj := time.Unix(sec, 22)
fmt.Println(timeObj) // 2022-02-22 22:22:22.000000022 +0800 CST
timeObj = time.UnixMilli(msec) // 毫秒级时间戳转为时间对象
fmt.Println(timeObj) // 2022-02-22 22:22:22 +0800 CST
timeObj = time.UnixMicro(usec) // 微秒级时间戳转为时间对象
fmt.Println(timeObj) // 2022-02-22 22:22:22 +0800 CST
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 时间间隔
time.Duration
是time
包定义的一个类型,它代表两个时间点之间经过的时间,以纳秒为单位。time.Duration
表示一段时间间隔,可表示的最长时间段大约 290 年。
time 包中定义的时间间隔类型的常量如下:
const (
Nanosecond Duration = 1
Microsecond = 1000 * Nanosecond
Millisecond = 1000 * Microsecond
Second = 1000 * Millisecond
Minute = 60 * Second
Hour = 60 * Minute
)
2
3
4
5
6
7
8
例如:time.Duration
表示 1 纳秒,time.Second
表示 1 秒。
# 时间操作
# Add
Go 语言的时间对象有提供 Add 方法如下:
func (t Time) Add(d Duration) Time
举个例子,求一个小时之后的时间:
func main() {
now := time.Now()
later := now.Add(time.Hour) // 当前时间加1小时后的时间
fmt.Println(later)
}
2
3
4
5
# Sub
求两个时间之间的差值:
func (t Time) Sub(u Time) Duration
返回一个时间段 t-u。如果结果超出了 Duration 可以表示的最大值/最小值,将返回最大值/最小值。要获取时间点 t-d(d 为 Duration),可以使用 t.Add(-d)。
# Equal
func (t Time) Equal(u Time) bool
判断两个时间是否相同,会考虑时区的影响,因此不同时区标准的时间也可以正确比较。本方法和用 t==u 不同,这种方法还会比较地点和时区信息。
# Before
func (t Time) Before(u Time) bool
如果 t 代表的时间点在 u 之前,返回真;否则返回假。
# After
func (t Time) After(u Time) bool
如果 t 代表的时间点在 u 之后,返回真;否则返回假。
# 定时器
使用time.Tick(时间间隔)
来设置定时器,定时器的本质上是一个通道(channel)。
func tickDemo() {
ticker := time.Tick(time.Second) //定义一个1秒间隔的定时器
for i := range ticker {
fmt.Println(i)//每秒都会执行的任务
}
}
2
3
4
5
6
# 时间格式化
time.Format
函数能够将一个时间对象格式化输出为指定布局的文本表示形式,需要注意的是 Go 语言中时间格式化的布局不是常见的Y-m-d H:M:S
,而是使用 2006-01-02 15:04:05.000
(记忆口诀为 2006 1 2 3 4 5)。
其中:
- 2006:年(Y)
- 01:月(m)
- 02:日(d)
- 15:时(H)
- 04:分(M)
- 05:秒(S)
补充
- 如果想格式化为 12 小时格式,需在格式化布局中添加
PM
。 - 小数部分想保留指定位数就写 0,如果想省略末尾可能的 0 就写 9。
// formatDemo 时间格式化
func formatDemo() {
now := time.Now()
// 格式化的模板为 2006-01-02 15:04:05
// 24小时制
fmt.Println(now.Format("2006-01-02 15:04:05.000 Mon Jan"))
// 12小时制
fmt.Println(now.Format("2006-01-02 03:04:05.000 PM Mon Jan"))
// 小数点后写0,因为有3个0所以格式化输出的结果也保留3位小数
fmt.Println(now.Format("2006/01/02 15:04:05.000")) // 2022/02/27 00:10:42.960
// 小数点后写9,会省略末尾可能出现的0
fmt.Println(now.Format("2006/01/02 15:04:05.999")) // 2022/02/27 00:10:42.96
// 只格式化时分秒部分
fmt.Println(now.Format("15:04:05"))
// 只格式化日期部分
fmt.Println(now.Format("2006.01.02"))
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 解析字符串格式的时间
对于从文本的时间表示中解析出时间对象,time
包中提供了time.Parse
和time.ParseInLocation
两个函数。
其中time.Parse
在解析时不需要额外指定时区信息。
// parseDemo 指定时区解析时间
func parseDemo() {
// 在没有时区指示符的情况下,time.Parse 返回UTC时间
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) // 2022-10-05 11:25:20 +0000 UTC
// 在有时区指示符的情况下,time.Parse 返回对应时区的时间表示
// RFC3339 = "2006-01-02T15:04:05Z07:00"
timeObj, err = time.Parse(time.RFC3339, "2022-10-05T11:25:20+08:00")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(timeObj) // 2022-10-05 11:25:20 +0800 CST
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
time.ParseInLocation
函数需要在解析时额外指定时区信息。