Golang中的日期与时间

9 minute read

Golang 的日期及时间

Golang 的日期及时间 Golang提供良好的支持与日期和时间的工作。在 Golang,我们不需要任何第三方软件包来管理时间和日期。Go 标准库的 time 包非常容易理解和实现。

Golang 默认的 time.time 时间类型表示具有纳秒精度的时间瞬间。它是一个没有导出字段的结构,这意味着您永远不需要使用点运算符来访问不同的字段。相反,可以使用各种方法来获得所需的数据。

如何得到当前的系统时间?

这是最常出现的问题之一。作为开发人员,我们遇到了许多这样的情况,需要获得系统的当前时间。观察下面的代码,了解如何得到当前的系统时间。

 1package main
 2
 3import (
 4    "fmt"
 5    "time"
 6)
 7
 8func main() {
 9    now := time.Now()
10    fmt.Println("Current time is:", now)
11}
1$ go run current_time.go 
2Current time is: 2021-11-03 20:57:06.294753357 +0530 IST m=+0.000030078

正如我们所知,UTC (Universal Coordinated time)被选为主要的时间标准,它避免了时区、夏时制等的混淆。在 Golang中,我们也可以得到当前系统时间(UTC)。让我们通过示例来了解如何以 UTC 表示当前系统时间。

 1package main
 2
 3import (
 4    "fmt"
 5    "time"
 6)
 7
 8func main() {
 9    now := time.Now().UTC()
10    fmt.Println("Current time is:", now)
11}
1$ go run current_time.go
2Current time is: 2021-11-03 15:32:48.441669614 +0000 UTC

日期和时间

我们还可以在 Golang 的 datetime 中访问不同的组件。为了访问年、月、日、小时、分钟和秒,我们可以对时间对象调用不同的函数。让我们通过下面的一个例子来理解。

 1package main
 2
 3import (
 4    "fmt"
 5    "time"
 6)
 7
 8func main() {
 9    now := time.Now()
10
11    fmt.Println("Year:", now.Year())
12    fmt.Println("Month:", now.Month())
13    fmt.Println("Day:", now.Day())
14    fmt.Println("Hour:", now.Hour())
15    fmt.Println("Minute:", now.Minute())
16    fmt.Println("Second:", now.Second())
17    fmt.Println("Nanosecond:", now.Nanosecond())
18}
1$ go run datetime.go
2Year: 2021
3Month: November
4Day: 3
5Hour: 21
6Minute: 21
7Second: 23
8Nanosecond: 806031374

Golang 的日期函数

我们可以为特定的日期创建一个时间对象。我们可以将年、月、日、小时、分钟、秒、纳秒和位置参数传递给 time.Date 函数。

 1package main
 2
 3import (
 4     "fmt"
 5     "time"
 6)
 7
 8func main() {
 9     t := time.Date(2020, time.November, 10, 23, 0, 0, 0, time.UTC)
10     fmt.Printf("Date-time is set to : %s\n", t.Local())
11}
1$ go run date_func.go 
2Date-time is set to : 2020-11-11 04:30:00 +0530 IST

使用 Golang 解析和格式化日期时间

日期和时间都可以有多种表示形式,Golang 提供了 parse () 函数来对其进行解析。Go 语言中的 Parse() 函数用于解析格式化的字符串,然后查找它形成的时间值。让我们观察下面的代码示例。在本例中,我们使用 parse() 函数使用布局来解析日期/时间。这个例子取自 Golang 的官方文件。time.Parse() 函数接受一个时间字符串和一个布局作为输入,并尝试创建一个新的 time 对象。

 1package main
 2
 3import (
 4	"fmt"
 5	"time"
 6)
 7
 8func main() {
 9	// Define the layout as constant
10	// Golang parse function will parse the given string in 
11	// same format as provided in layout.
12	const longForm = "Jan 2, 2006 at 3:04pm (MST)"
13	t, _ := time.Parse(longForm, "Feb 3, 2013 at 7:54pm (PST)")
14	fmt.Println(t)
15
16	const shortForm = "2006-Jan-02"
17	t, _ = time.Parse(shortForm, "2013-Feb-03")
18	fmt.Println(t)
19
20	// Some valid layouts are invalid time values, due to format specifiers
21	// such as _ for space padding and Z for zone information.
22	// For example the RFC3339 layout 2006-01-02T15:04:05Z07:00
23	// contains both Z and a time zone offset in order to handle both valid options:
24	// 2006-01-02T15:04:05Z
25	// 2006-01-02T15:04:05+07:00
26	t, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
27	fmt.Println(t)
28	t, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05+07:00")
29	fmt.Println(t)
30	_, err := time.Parse(time.RFC3339, time.RFC3339)
31	fmt.Println("error", err) // Returns an error as the layout is not a valid time value
32
33}
1$ go run parse_time.go 
22013-02-03 19:54:00 +0000 PST
32013-02-03 00:00:00 +0000 UTC
42006-01-02 15:04:05 +0000 UTC
52006-01-02 15:04:05 +0700 +0700
6error parsing time "2006-01-02T15:04:05Z07:00": extra text: "07:00"

Golang 的持续时间

简单地说,持续时间是两个时刻之间经过的时间。技术上,在Golang持续时间表示两个瞬间之间的经过时间,作为一个整数64纳秒计数。这代表将最长的持续时间限制在大约290年。让我们来看一个例子,如何计算方法调用之间的运行时间。观察下面的代码函数 t1.Sub(t0) 是用来计算运行时间的。

 1package main
 2
 3import (
 4	"fmt"
 5	"time"
 6)
 7
 8func expensiveCall() {}
 9
10func main() {
11	t0 := time.Now()
12	expensiveCall()
13	t1 := time.Now()
14	fmt.Printf("The call took %v to run.\n", t1.Sub(t0))
15}
1$ go run elapsed.go
2The call took 64ns to run.

加减和比较时间

Golang 提供各种功能,可对时间对象执行多种操作。通过这些方法,我们可以添加时间或时间相减,得到两个时间之间的差,并比较两个时间,看看哪个时间在另一个时间之后。让我们通过例子来理解这一点。

在下面的例子中,我们使用了两个函数: time.Add() 加/减去时间 和 time.AddDate()添加/减去日期。

 1package main
 2
 3import (
 4	"fmt"
 5	"time"
 6)
 7
 8func main() {
 9	// Adding time
10
11	// Adding 5 minutes 
12	currentTime := time.Now().UTC()
13	inFiveMinutes := currentTime.Add(time.Minute * 5)
14	fmt.Println("Five min in future", inFiveMinutes)
15
16	// 5 minutes ago
17	fiveMinutesAgo := currentTime.Add(-time.Minute * 5)
18	fmt.Println("Five min in past", fiveMinutesAgo)
19
20
21	// Adds years, months, and days
22	
23	// inOneMonth is 1 month in the future
24	inOneMonth := currentTime.AddDate(0, 1, 0)	
25	fmt.Println("One month in future", inOneMonth)
26
27
28	oneDayAgo := currentTime.AddDate(0, 0, -1)
29	fmt.Println("One day ago ", oneDayAgo)
30}
1Five min in future 2021-11-05 05:18:53.982233815 +0000 UTC
2Five min in past 2021-11-05 05:08:53.982233815 +0000 UTC
3One month in future 2021-12-05 05:13:53.982233815 +0000 UTC
4One day ago  2021-11-04 05:13:53.982233815 +0000 UTC

现在让我们举一个例子,我们需要得到两个时间实例之间的差。 time.Sub() 获取两个时间实例之间的差。

 1package main
 2
 3import (
 4	"fmt"
 5	"time"
 6)
 7
 8func main() {
 9	// Getting difference between time instances
10	startTime := time.Date(2019, 1, 1, 3, 0, 0, 0, time.UTC)
11	endTime := time.Date(2020, 1, 1, 3, 0, 0, 0, time.UTC)
12
13	difference := endTime.Sub(startTime) 
14	fmt.Printf("The time difference is = %v\n", difference)
15}
1$ go run time_diff.go 
2The time difference is = 8760h0m0s

现在让我们举一个例子,我们需要找出哪个时间先于其他时间出现, 我们会利用 time.After() 函数。这是非常常见的用例,用于需要比较时间的地方。我们还将看看如何检查时间是否相等–就是使用 time.Equal()

 1package main
 2
 3import (
 4	"fmt"
 5	"time"
 6)
 7
 8func main() {
 9
10	first := time.Date(2022, 2, 1, 3, 0, 0, 0, time.UTC)
11	second := time.Date(2021, 2, 1, 12, 0, 0, 0, time.UTC)
12	third := time.Date(2021, 2, 1, 12, 0, 0, 0, time.UTC)
13
14	isFirstAfter := first.After(second)
15	fmt.Printf("Is first come after %t\n",isFirstAfter)
16	isThirdEqualSecond := third.Equal(second)
17	fmt.Printf("Is third equal second %t\n",isThirdEqualSecond)
18
19}
1$ go run time_check.go 
2Is first come after true
3Is third equal second true

Sleep & time ticker

在 Golang中,我们可以使用 time.Sleep() 暂停代码的执行 。请记住,这是同步的,它会阻塞当前 Go 线程(routine)。

 1package main
 2
 3import (
 4	"fmt"
 5	"time"
 6)
 7
 8func main() {
 9	// Sleeping for 5 second
10	fmt.Printf("Current Unix Time: %v\n", time.Now().Unix())
11	time.Sleep(5 * time.Second)
12	fmt.Printf("Current Unix Time: %v\n", time.Now().Unix())
13}
1$ go run sleep_5second.go
2Current Unix Time: 1636090412
3Current Unix Time: 1636090417

Golang ticker 是用来在特定的时间间隔执行代码的。如果我们需要在一个固定的时间间隔内做一些事情(比如说每秒或者每分钟) ,我们可以使用 Golang time.Ticker() 函数。举个例子。在下面的代码中,我们每秒钟打印一次语句。

 1package main
 2
 3import (
 4	"fmt"
 5	"time"
 6)
 7
 8func printSomethingEverySecond() {
 9    ticker := time.NewTicker(time.Second)
10    for range ticker.C {
11	fmt.Printf("Current Unix Time: %v\n", time.Now().Unix())
12    }
13}
14func main() {
15	printSomethingEverySecond()
16}
1$ go run ticker_demo.go 
2Current Unix Time: 1636090736
3Current Unix Time: 1636090737
4Current Unix Time: 1636090738
5Current Unix Time: 1636090739
6Current Unix Time: 1636090740
7Current Unix Time: 1636090741
8Current Unix Time: 1636090742
9...