在许多场合,你将不得不编写有必要处理时刻的代码。你能够写一个时钟程序,或者在你的代码中丈量两点之间的时刻差。无论是哪种办法,知道怎么在Go中处理时刻数据是很重要的。这很简略,了解一些风趣的函数能够协助你节省时刻。在Go中处理时刻数据需求你从Go标准库中导入 time 包。这个包有许多办法和类型供你运用,但我选取了最常用的办法和类型,并在这篇文章中进行了描述。假如你想看更多关于这个主题的信息,请检查time包的文档页面。

获取时刻

这可能是软件包中最常用的办法。咱们怎么知道当时的时刻呢?像这样:

t := time.Now()
fmt.Println(t)
2023-04-16 23:54:45.924965 +0800 CST m=+0.000152293

这便是当时的时刻。这是很麻烦的,所以我将把它分解成几个部分。

  • 2023-02-06:年月日。
  • 23:01:48.9983151:时、分、秒
  • 0800:与 GMT 的时差。
  • CST:您地点的当时时区。
  • m=+0.000152293: 单调时钟读数。

咱们将在本文后边介绍单调时钟。 咱们现在能够继续前进。

有没有更好的办法来格局化这个?

你打赌。

t := time.Now()
fmt.Println(t.Year())
fmt.Println(t.Month())
fmt.Println(t.Day())
fmt.Println(t.Date())
fmt.Println(t.Hour())
fmt.Println(t.Minute())
fmt.Println(t.Second())
2023
April
17
2023 April 17
0
3
31

以下是怎么提取时刻的每个元素。 很简略,对吧?

咱们怎么以更漂亮的格局打印它?

fmt.Printf("%d %d %d\n", t.Year(), t.Month(), t.Day())
2023 4 17

您能够看到咱们怎么运用 fmt.Printf 函数来依据自己的喜爱格局化时刻。

但是假如咱们想用名字显现月份,比方二月而不是 2 怎么办? 假如咱们想以 12 小时制而不是 24 小时制显现时刻怎么办? 你能够看到它是怎么很快变得复杂的。

有一种更好的格局化时刻的办法

走运的是,咱们有 time.Format 函数来协助咱们。 让咱们看看它是怎么工作的。

fmt.Println(t.Format("Mon Jan 2 15:04:05 2006 MST"))
fmt.Println(t.Format("Mon Jan 2 15:04:05"))
fmt.Println(t.Format("2006/01/02"))
fmt.Println(t.Format("3:04PM"))
fmt.Println(t.Format("15:04PM"))
Mon Apr 17 00:06:21 2023 CST
Mon Apr 17 00:06:21
2023/04/17
12:06AM
00:06AM

我以为这是我刚开始学习这个主题时最让我失望的部分。 这也是您能够看到言语设计者有多么厚颜无耻的部分。

咱们能够看到 time.Format 接受一个字符串,该字符串表示咱们期望时刻选用的格局。这是古怪的部分,因为 Go 对格局字符串的格局非常非常考究。

Mon Apr 17 00:06:21 2023 CST

格局字符串有必要是该字符串的变体,否则代码会打印出古怪的时刻。 风趣的是,假如排除 Mon,格局字符串的每个元素都代表一个整数。 Jan 是 1,2 是 2,15 是 3。

1 2 3 4 5 6 -7

不过,从上面的代码中,您能够看到咱们怎么按照咱们想要的办法格局化咱们的时刻。 并且咱们不用编写额定的函数来将小时转化为 12 或 24 小时制,或者将每个整数映射到月份。

您也能够运用预界说的格局,如下所示:

fmt.Println(time.UnixDate)
fmt.Println(time.RFC3339)
Mon Jan _2 15:04:05 MST 2006
2006-01-02T15:04:05Z07:00

检查文档以了解更多格局。

不同的时区呢?

如上所示,系统会自动检测时区。 但是,在某些情况下,您可能需求显现不同时区的时刻。

nt := time.Now()
lt := time.Now().Local()
ut := time.Now().UTC()
fmt.Println(nt)
fmt.Println(lt)
fmt.Println(ut)
2023-04-17 00:11:10.214751 +0800 CST m=+0.000135417
2023-04-17 00:11:10.214751 +0800 CST
2023-04-16 16:11:10.214751 +0000 UTC

Local() 获取本地时区,这与 time.Now() 会自动检测到的时刻相同。 调用 UTC() 会将时区转化为 UTC。

但是,假如咱们需求更强大的东西怎么办?

l, _ := time.LoadLocation("UTC")
fmt.Printf("%s\n", nt.In(l))
l, _ = time.LoadLocation("Europe/London")
fmt.Printf("%s\n", nt.In(l))
l, _ = time.LoadLocation("America/Los_Angeles")
fmt.Printf("%s\n", nt.In(l))
l, _ = time.LoadLocation("Asia/Seoul")
fmt.Printf("%s\n", nt.In(l))
2023-04-16 16:12:00.918525 +0000 UTC
2023-04-16 17:12:00.918525 +0100 BST
2023-04-16 09:12:00.918525 -0700 PDT
2023-04-17 01:12:00.918525 +0900 KST

time.LoadLocation 将加载您挑选的言语环境。 您能够运用此成果通过传入你的 time.In 来转化您的时刻。

您还能够从字符串中读取时刻

在许多情况下,您将不得不读入一个字符串。 一般,这些将是时刻戳。 在这些时刻戳字符串上运用时刻库的函数不是很好吗?

默认情况下,时刻库适用于 time.Time 类型。 但是,咱们能够运用 time.Parse 来解析这些时刻戳字符串。

timestamp := "2023-02-06 23:49:01"
ts, err := time.Parse("2006-01-02 15:04:05", timestamp)
if err != nil {
    fmt.Println(err)
}
fmt.Println(ts)
2023-02-06 23:49:01 +0000 UTC

您还能够运用上述 Format 办法格局化 ts。

等等,什么是单调时钟?

让咱们回到这个论题。 这听起来比实际情况要可怕得多。

您的计算机有一个计时时钟。 很有可能这次相当不稳定。 有没有过在去另一个国家旅行后你的时钟慢了几个小时的经历? 是否曾经需求从头设置您的时钟以使其与您的手表相匹配? 这个时钟叫做挂钟,很简略改动。

尽管挂钟拿手报时,但不合适丈量时刻。 例如,看看这段代码。

t1 := time.Now()
fmt.Println(t1)
time.Sleep(time.Second)
t2 := time.Now()
fmt.Println(time.Now())
fmt.Println(t2.Sub(t1))
2023-04-17 00:15:32.65858 +0800 CST m=+0.000109168
2023-04-17 00:15:33.660121 +0800 CST m=+1.001672543
1.001563166s

上面的代码丈量了 t1 和 t2 之间通过的时刻。 这看起来很明显,因为咱们在声明 t2 之前等待了一秒钟。 但是,假如咱们以某种办法设法在该跨度内切换咱们的操作系统时刻设置呢? 假如咱们将系统时钟添加 4 小时,是否意味着 t1 和 t2 之间通过的时刻为 4 小时 1 秒? 这是荒唐的!

这便是 Go 运用单调时钟来丈量时刻的原因。 从打印出来的时刻里的m值能够看出,时刻差大约是一秒。 单调时钟允许准确丈量时刻。

定论

咱们对时刻的概念如此熟悉,以至于咱们倾向于以为咱们对它的了解是理所当然的。 然而,时刻往往是在计算机中表示的更令人沮丧的事物之一。 走运的是,Go 开发人员已经从咱们这儿抽象出了大部分原始转化,这样咱们就能够运用 time 包的简略易懂的功用。 这篇文章涵盖了许多必要的功用,但假如您需求细节,您能够随时参阅官方文档。