开发应用程序的过程中,经常需要记录某些操作的时间或者格式化时间戳,因此大部分编程语言都会有操作时间的库,Go
语言当然也不例外。
Go
语言对时间的操作能力集中标准库time
包里,所以在这篇文章中,我们一起来学习time
包的使用。
获取当前时间
在Go语言中,要获取当前的时间非常简单,只要调用time
包的Now()
函数即可:
fmt.Println(time.Now())
上面代码的输出结果是:
2023-06-16 09:44:58.726134 +0800 CST m=+0.000151257
上面结果的各部分意义是:
2023-06-06
:表示日期09:44:58.726134
:表示时间+0800 CST
:时区,这里是指东八区m=+0.000151257
:单调时间,用于表示两个时间点的长度。
时间戳与时区
时区
地球上各个地区因为经度的不同被划分为24个时区,这24个时区以零时区(中时区)开始划分为东西各12
个时区,相邻两个时区之间相差一个小时,其计算规则是向东每跨过一个时区增加1个小时,向西每跨一个时间减去1个小时:
假设此时零时区是上午9:00
的话,那么其他各个时区的时间根据所在时区会有所不同,下面表格列举了几个时区的时间:
西七区(加里福利亚州) | 西五区(纽约) | 西四区(圣地亚哥) | 零时区 | 泰国(东7区) | 中国(东八区) | 日本(东九区) |
---|---|---|---|---|---|---|
1:00 | 4:00 | 7:00 | 9:00 | 16:00 | 17:00 | 18:00 |
世界标准时间的缩写为UTC
,UTC
也表示零时区,如果我们想表示某个时区的话,比如东八区,其写法为UTC+8
,西五区则为UTC-5
。
另外,时区一般有自己的缩写,比如PRC
表示中国标准时间,Asia/Shanghai
也是指中国时间,也就是说PRC
、Asia/Shanghai
与UTC+8
都是表示东八区的中国时间。
时间戳
时间戳
是指以格林尼治1970年1月1日 00:00:00为起点的秒数,时间戳不受时区的影响,所在在地球上任何一个地方在某一时刻获得的时间戳都是一样的。
在Go
语言中,要获得当前时间戳也非常简单:
fmt.Println(time.Now().Unix())
time.Time
Time
前面我们通过time.Now()
获取当前时间,实际上该函数返回一个time
包下的Time
结构体,Time
结构体表示一个时间对象,大部分操作时间的功能都集中在这个结构体中:
time.Now().Year() //获取当前年份
time.Now().Month() //获取当前月份
时间格式规则
有了表示时间的对象后,如果想按照我们想要的格式输出可以调用Time
的Format()
方法,如果你接触过其他编程语言(比如PHP
),这时可能会觉得需要给Format()
传进入类似下面的参数:
Y-m-d H:i:s
在上面给出的格式中,Y
表示年份,m
表示月份,d
表示日期,H
表示小时,i
表示分钟,s
表示秒。
在其他编程语言中,使用以上格式进行时间格式化处理,会得到下面这样的日期:
2023-06-18 18:32:30
不过在Go语言中,要想将得到同样的结果,你需要这样做:
time.Now().Format("2006-01-02 15:04:05")
上面的代码的运行结果同样是:
2023-06-18 18:32:30
从上面的格式可以看出2006-01-02 15:04:05
相当于其他编程语言的Y-m-d H:i:s
,这就是Go语言在时间处理方面与其他编程语言的差异。
Go语言格式化时间的规则如下表格所示:
格式 | 说明 |
---|---|
2006或者06 | 年 |
January或01或1 | 月 |
Mon或者Monday | 星期 |
2或_2或者02 | 日期 |
__2或002 | 一年中的第几天 |
15或3或03 | 小时 |
4或04 | 分钟 |
5或05 | 秒 |
PM | AM/PM |
-0700 | 时区,±hhmm |
-07:00 | 时区,±hh:mm |
-07 | 时区,±hh |
-070000 | 时区, ±hhmmss |
-07:00:00 | 时区, ±hh:mm:ss |
因此,如果我们想把当前时间按下面的时间格式显示的话:
年-月-日 时:分:秒 星期几 时区
我们的代码需要这样写:
time.Now().Format("2006-01-02 15:04:05 Monday -0700")
其实,如果总是需要自己写上面的格式字符串也很麻烦,因此time
包下定义了很多常量,可以直接调用:
Layout = "01/02 03:04:05PM '06 -0700"
ANSIC = "Mon Jan _2 15:04:05 2006"
UnixDate = "Mon Jan _2 15:04:05 MST 2006"
RubyDate = "Mon Jan 02 15:04:05 -0700 2006"
RFC822 = "02 Jan 06 15:04 MST"
RFC822Z = "02 Jan 06 15:04 -0700"
RFC850 = "Monday, 02-Jan-06 15:04:05 MST"
RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700"
RFC3339 = "2006-01-02T15:04:05Z07:00"
RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
Kitchen = "3:04PM"
Stamp = "Jan _2 15:04:05"
StampMilli = "Jan _2 15:04:05.000"
StampMicro = "Jan _2 15:04:05.000000"
StampNano = "Jan _2 15:04:05.000000000"
DateTime = "2006-01-02 15:04:05"
DateOnly = "2006-01-02"
TimeOnly = "15:04:05"
Date
如果不是想获取当前时间,而是要指定某个时间,可以调用Date()
函数构建一个指定日期Time
对象,Date()
函数的签名如下:
func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time
可以看到,调用函数Date()
需要的参数可以精确到纳秒:
fmt.Println(time.Date(2023, time.Month(1), 2, 2, 2, 2, 0, time.Local))
Parse
有时候我们接收用户与时间相关请求参数时,得到往往是一个时间格式的字符串,比如2023-06-02 10:00:00
:
t, _ := time.Parse(time.DateTime, "2023-06-02 10:00:00")
fmt.Println(t.Unix())
格式化时间戳
通常我们都是以时间戳的形式将时间保存在数据库中,当需要展示给用户时,则需要将时间戳格式化,Go语言支持秒,毫秒,微秒等时间戳的格式:
t := time.Unix(1685700000, 0)
fmt.Println(t.Format(time.DateTime))
按时区显示时间
有时候我们需要根据用户所在时区显示对应的时间,在time
包里,用Location
结构体表示一个时区对象,可以使用time
包的LoadLocation()
函数加载本地预先定义的时区数据
loc1, err := time.LoadLocation("Asia/Shanghai")
loc2, err := time.LoadLocation("PRC")
也可以使用FixeZone
函数自己定义一个时区名称:
beijing := time.FixedZone("Beijing", +8*60*60)
有了Location
对象,我们可以将显示不同时区的时间:
package main
import (
"fmt"
"time"
)
func main() {
ch, _ := time.LoadLocation("PRC")
t := time.Date(2023, time.June, 19, 11, 43, 0, 0, ch)
fmt.Println("中国时间是:", t)
jp := time.FixedZone("jp", +(9 * 60 * 60))
t2 := t.In(jp)
fmt.Println("日本时间是:", t2)
}
time.Duration
如果要比较两个时刻之间的时间长度,可以调用Time的Sub
方法,这个函数可以计算两个时刻的长度,并返回一个表示时间段的Duration
结构体:
package main
import (
"fmt"
"time"
)
func main() {
t1, _ := time.Parse(time.DateTime, "2023-06-01 16:00:00")
t2, _ := time.Parse(time.DateTime, "2023-06-02 16:00:00")
d := t2.Sub(t1)
fmt.Println(d)
}
上面例子运行结果为:
24h0m0s
当我们想在某个时刻上叠加一个时间段时,也可以调用time包的ParseDuration()
函数构建一个Duration
结构体并传给Time
结构体的Add()
方法。
ParseDuration()
函数的参数为一个表示时间段的字符串,比如1h
,2days
:
package main
import (
"fmt"
"time"
)
func main() {
d, _ := time.ParseDuration("4h")
t := time.Now().Add(d)
fmt.Println(t)
}
小结
Go
的标准库time
包提供了完整操作对时间的格式式和测量等功能,虽然用法与其他编程语言稍有差异,但是也非常容易掌握。