Go下time包使用及各种转换

时间和日期是我们编程中经常会用到的,本文主要介绍了 Go 语言内置的 time 包的基本用法。time 包提供了一些关于时间显示和测量用的函数。

1如何正确表示时间?

公认最准确的计算应该是使用“原子震荡周期”所计算的物理时钟了(Atomic Clock, 也被称为原子钟),这也被定义为标准时间(International Atomic Time)。

而我们常常看见的 UTC(Universal Time Coordinated,世界协调时间)就是利用这种 Atomic Clock 为基准所定义出来的正确时间。UTC 标准时间是以 GMT(Greenwich Mean Time,格林尼治时间)这个时区为主,所以本地时间与 UTC 时间的时差就是本地时间与 GMT 时间的时差。

1
UTC + 时区差 = 本地时间

国内一般使用的是北京时间,与 UTC 的时间关系如下:

1
UTC + 8 个小时 = 北京时间

在Go语言的 time 包里面有两个时区变量,如下:

  • time.UTC:UTC 时间
  • time.Local:本地时间

同时,Go语言还提供了 LoadLocation 方法和 FixedZone 方法来获取时区变量,如下:

1
FixedZone(name string, offset int) *Location

其中,name 为时区名称,offset 是与 UTC 之前的时差。

1
LoadLocation(name string) (*Location, error)

其中,name 为时区的名字。

1
2
3
4
5
6
7
8
9
// 中国没有夏令时,使用一个固定的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

2时间戳

时间戳是自 1970 年 1 月 1 日(08:00:00GMT)至当前时间的总毫秒数,它也被称为 Unix 时间戳(UnixTimestamp)

1
2
3
4
5
6
7
8
9
// 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)
}

3时间格式化

时间类型有一个自带的 time.Format 方法进行格式化,需要注意的是Go语言中格式化时间模板不是常见的Y-m-d H:M:S ,。

而是使用 2006-01-02 15:04:05.000(记忆口诀为 6 1 2 3 4 5 )。

  • 如果想格式化为12小时格式,需在格式化布局中添加PM
  • 小数部分想保留指定位数就写0,如果想省略末尾可能的0就写 9。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 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"))
}

4时间格式的转换

1 时间戳转时间字符串 (int64 —> string)

1
2
3
4
5
timeUnix:=time.Now().Unix()   //已知的时间戳

formatTimeStr:=time.Unix(timeUnix,0).Format("2006-01-02 15:04:05")

fmt.Println(formatTimeStr) //打印结果:2023-02-20 13:30:39

2 时间字符串转时间(string —> Time)

1
2
3
4
5
6
7
formatTimeStr=”2023-02-20 13:30:39

formatTime,err:=time.Parse("2006-01-02 15:04:05",formatTimeStr)

if err==nil{
fmt.Println(formatTime) //打印结果:2023-02-20 13:30:39 +0000 UTC
}

3 时间字符串转时间戳 (string —> int64)

1
2
3
4
5
// ======= 将时间字符串转换为时间戳 =======
timeTemplate1 := "2006-01-02 15:04:05"
t1 := "2019-01-08 13:50:30" //外部传入的时间字符串
stamp, _ := time.ParseInLocation(timeTemplate1, t1, time.Local) //使用parseInLocation将字符串格式化返回本地时区时间
log.Println(stamp.Unix()) //输出:1546926630

4 时间戳获取日期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 获取时间,该时间带有时区等信息,获取的为当前地区所用时区的时间  
timeNow := time.Now()
// 获取时间戳
unix := time.Now().Unix()
// 获取UTC时区的时间
utcTime := time.Now().UTC()
// go语言固定日期模版
timeLayout := "2006-01-02 15:04:05"
// time.Unix的第二个参数传递0或10结果一样,因为都不大于1e9
timeStr := time.Unix(unix, 0).Format(timeLayout)
fmt.Println(timeNow, unix, utcTime, timeStr)

// 获取年月日,其中month为string,也就是英文的月份
year, month, day := time.Now().Date()
fmt.Printf("year is %+v, month is %+v, day is %+v \n", year, month, day)

补充

根据mysql中timestamp字段获取时间字符串

1
2
3
4
5
如下实例,其中lectureModel的create_time字段为timestamp  
lecture, err := ll.lectureModel.FindOne(req.LectureId)
// 获取当前时区unix时需要减去3600*8,原因是mysql存储的时间为UTC时间
unixT := lecture.CreateTime.Unix() - 3600*8
timeStr := time.Unix(unixT, 0).Format(DateDetailLayout)

参考资料:

[go语言时间和时间戳转换][https://www.cnblogs.com/akidongzi/p/12801574.html]

[Go语言基础之time包][https://www.liwenzhou.com/posts/Go/go-time/#autoid-1-5-0]