ZetCode

Go 日期时间

最后修改日期:2025 年 5 月 4 日

在本文中,我们将展示如何在 Golang 中处理日期和时间。time 包提供了测量和显示时间的功能。

定义

日历时间,也称为绝对时间,指定了时间连续体上的一个精确点。它通常使用包含日期、时间、时区的时间戳来表示——例如,2021 年 7 月 29 日下午 13:02:05 CET。日历时间用作记录事件、安排活动和同步进程的参考。

时间间隔 表示两个日历时间之间的连续跨度。根据上下文,它可以从纳秒到世纪不等。例如,2020 年 2 月 20 日 15:00 到 19:00 的时间段构成了一个四小时的时间间隔。在物理学、计算机科学和项目管理等领域,需要精确测量持续时间,时间间隔至关重要。

一个时间间隔的经过时间 指的是它的持续时间,表示其起点和终点之间的差值。它可以以秒、分钟、小时或天等单位表示。例如,38 分钟的经过时间可能指一次会议或一段旅程的持续时间。与指定确切时刻的日历时间不同,经过时间侧重于测量时间流逝。

时间量 是多个经过时间的累积总和,这些时间可能发生在不同的实例,并且不一定连续。例如,如果一个人在几天内花费了十一个小时来完成一个项目,那么无论何时记录这些小时,投入到该任务的总时间量都是十一个小时。这个概念在生产力分析和日程安排中很有用。

周期 是两个事件之间的经过时间,通常表示过程或活动中的阶段。在物理学和工程学中,“周期”一词可以指重复事件一个完整周期的持续时间,例如钟摆一次来回摆动所需的时间。在人类活动中,周期可能表示一个工作班次、教育中的一个学期或商业中的一个财政季度。

CPU 时间 指的是中央处理单元 (CPU) 为程序或操作系统主动执行指令所花费的时间量。它不包括 CPU 未执行计算时的空闲或等待时间。CPU 时间以时钟周期或秒为单位进行测量,是计算中的一个重要指标,尤其是在性能分析和优化方面。高 CPU 时间使用量可能表明计算密集或处理效率低下。

纪元 是一个时间参考点,特定时代从此开始。它常用于计算、天文学和历史中。例如,Unix 纪元 是 Unix 基于的时间计数的指定起点:1970 年 1 月 1 日 00:00:00 UTC (ISO 8601: 1970-01-01T00:00:00Z)。许多操作系统和编程语言使用此纪元来计算时间差和时间戳。

挂钟时间,也称为实际时间或壁钟时间,是使用标准计时器(如手表、挂钟或电子计时设备)测量的经过时间。它常用于性能基准测试和实时应用程序。该术语源于参考安装在墙上的物理时钟的实践。挂钟时间与 CPU 时间不同,CPU 时间仅计算主动处理时间段。此外,由于系统延迟、时钟漂移以及夏令时调整等因素,可能会出现差异。

Go 当前时间示例

以下示例演示了如何在 Go 中检索和显示当前日期和时间。这是通过使用 time 包实现的,该包提供了用于处理与时间相关的操作的强大功能。

main.go
package main

import (
    "fmt"
    "time"
)

func main() {

    now := time.Now()
    fmt.Println("Current datetime:", now)
}

在此示例中,time 包中的 Now 函数用于获取当前的日期和时间。然后将结果打印到控制台,展示了 time 包提供的精度和细节。

$ go run main.go
Current datetime: 2022-05-29 17:46:47.069217048 +0200 CEST m=+0.000013004

Go UTC 时间

我们的地球是一个绕其轴线旋转的球体,导致太阳在不同地点在不同时间升起。这种大约需要 24 小时的旋转导致世界被划分为 24 个时区。每个时区内的当地时间通常会根据夏令时进一步调整。

为了满足统一全球时间标准的需求,制定了 UTC(协调世界时)。UTC 消除了时区和夏令时调整造成的混淆。它广泛用于航空、天气预报、空中交通管制和其他全球应用。与当地时间不同,UTC 在全年保持不变。

$ timedatectl
               Local time: Ne 2022-05-29 17:48:07 CEST
           Universal time: Ne 2022-05-29 15:48:07 UTC
                 RTC time: Ne 2022-05-29 15:48:07
                Time zone: Europe/Bratislava (CEST, +0200)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

在此示例中,当地时区是欧洲中部夏令时 (CEST),UTC 偏移量为 +2 小时。此偏移量表示本地时间与 UTC 之间的差异。

main.go
package main

import (
     "fmt"
     "time"
)

func main() {

     utc := time.Now().UTC()
     fmt.Println(utc)
}

上面的示例演示了如何使用 time 包中的 UTC 函数检索当前的 UTC 时间。这确保了时间以全球一致的格式显示。

$ go run main.go
2022-05-29 15:50:07.413562417 +0000 UTC

Go 日期时间部分

以下示例说明了如何提取和显示当前日期和时间的各个组件,例如年、月、日、小时、分钟、秒和纳秒。

main.go
package main

import (
    "fmt"
    "time"
)

func main() {

    now := time.Now()

    fmt.Println("Year:", now.Year())
    fmt.Println("Month:", now.Month())
    fmt.Println("Day:", now.Day())
    fmt.Println("Hour:", now.Hour())
    fmt.Println("Minute:", now.Minute())
    fmt.Println("Second:", now.Second())
    fmt.Println("Nanosecond:", now.Nanosecond())
}

在此示例中,time 包提供了用于访问当前日期时间每个组件的专用函数。这些函数允许对日期时间数据进行精确而详细的操作。

$ go run main.go
Year: 2022
Month: May
Day: 29
Hour: 17
Minute: 50
Second: 38
Nanosecond: 266573694

Go Date 函数

Go 中的 time.Date 函数允许开发人员通过指定年、月、日、小时、分钟、秒、纳秒和位置来创建日期时间对象。此函数特别适用于生成特定时间戳或初始化日期时间值以供进一步操作。

main.go
package main

import (
     "fmt"
     "time"
)

func main() {
     t := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
     fmt.Printf("Go launch date: %s\n", t.Local())
}

在示例中,我们创建了一个代表 Go 编程语言发布日期的日期时间对象。time.Date 函数用于设置精确的时间点,包括 UTC 时区。

传递给 time.Date 函数的参数包括年、月、日、小时、分钟、秒、纳秒和位置。这种详细程度确保了对所创建的日期时间对象的精确控制。

生成的日期时间对象可以根据需要进行格式化或操作,这使得 time.Date 函数成为在 Go 中处理日期和时间的通用工具。

$ go run main.go
Go launch date: 2009-11-11 00:00:00 +0100 CET

Go 格式化日期时间

Go 不使用典型的 yyyy-mm-dd 格式说明符;它使用以下参考日期时间格式

Mon Jan 2 15:04:05 -0700 MST 2006

我们根据我们如何构建此特定参考日期时间来格式化时间。

main.go
package main

import (
    "fmt"
    "time"
)

func main() {

    now := time.Now()

    fmt.Println("Time: ", now.Format("15:04:05"))
    fmt.Println("Date:", now.Format("Jan 2, 2006"))
    fmt.Println("Timestamp:", now.Format(time.Stamp))
    fmt.Println("ANSIC:", now.Format(time.ANSIC))
    fmt.Println("UnixDate:", now.Format(time.UnixDate))
    fmt.Println("Kitchen:", now.Format(time.Kitchen))
}

该示例以自定义和预定义格式显示当前时间。

fmt.Println("Date:", now.Format("Jan 2, 2006"))

这是自定义日期时间格式的示例。

fmt.Println("ANSIC:", now.Format(time.ANSIC))

这是预定义格式的示例。

$ go run main.go
Time:  17:51:45
Date: May 29, 2022
Timestamp: May 29 17:51:45
ANSIC: Sun May 29 17:51:45 2022
UnixDate: Sun May 29 17:51:45 CEST 2022
Kitchen: 5:51PM

Go 解析日期时间

Go 中的 Parse 函数用于将格式化字符串转换为时间值。此函数对于解释和处理各种格式的日期和时间字符串至关重要。

布局参数定义了输入字符串的预期格式。它使用参考时间来指定结构。ANSIC、UnixDate 和 RFC3339 等预定义布局为常见格式提供了方便的选项。

main.go
package main

import (
     "fmt"
     "log"
     "time"
)

func main() {

     vals := []string{"2021-07-28", "2020-11-12", "2019-01-05"}

     for _, val := range vals {

          t, err := time.Parse("2006-01-02", val)

          if err != nil {

               log.Fatal(err)
          }

          fmt.Println(t)
     }
}

在示例中,我们使用 Parse 函数解析了三个日期字符串。每个字符串都被转换为一个时间值,然后可以用于进一步的操作或比较。

$ go run main.go
2021-07-28 00:00:00 +0000 UTC
2020-11-12 00:00:00 +0000 UTC
2019-01-05 00:00:00 +0000 UTC

Go 日期时间算术

Go 中的 AddAddDate 函数允许对日期时间值执行算术运算。这些函数对于计算将来或过去的日期和时间很有用。

在示例中,我们演示了三个操作:添加 27 小时,添加 2 年、10 个月和 11 天,以及减去 6 小时。这些操作说明了 Go 中日期时间算术的灵活性。

main.go
package main

import (
     "fmt"
     "time"
)

func main() {

     now := time.Now()

     t1 := now.Add(time.Hour * 27)
     fmt.Println(t1.Format(time.UnixDate))

     t2 := now.AddDate(2, 10, 11)
     fmt.Println(t2.Format(time.UnixDate))

     t3 := now.Add(-time.Hour * 6)
     fmt.Println(t3.Format(time.UnixDate))
}

在代码示例中,我们执行了三个算术运算。

t1 := now.Add(time.Hour * 27)

我们添加 27 小时。

t2 := now.AddDate(2, 10, 11)

我们添加 2 年、10 个月和 11 天。

t3 := now.Add(-time.Hour * 6)

我们减去 6 小时。

$ go run main.go
Mon May 30 20:52:29 CEST 2022
Wed Apr  9 17:52:29 CEST 2025
Sun May 29 11:52:29 CEST 2022

Go 日期时间 持续时间

Go 中的 Duration 表示两个时间点之间的经过时间。它表示为 int64 纳秒计数,为时间计算提供高精度。

Sub 函数计算两个时间点之间的持续时间。这对于测量时间间隔或确定特定日期和时间之间的差异很有用。

Since 函数是 time.Now().Sub(t) 的简写。它计算自指定日期时间以来经过的时间,使其成为跟踪相对于当前时间的持续时间的理想选择。

main.go
package main

import (
     "fmt"
     "time"
)

func main() {

     t1 := time.Date(2020, time.November, 10, 23, 0, 0, 0, time.UTC)
     t2 := time.Date(2021, time.July, 28, 16, 22, 0, 0, time.UTC)

     elapsed := t2.Sub(t1)

     fmt.Println(elapsed)
}

该示例计算了两个时间点之间的经过时间。

$ go run main.go
6233h22m0s
main.go
package main

import (
     "fmt"
     "time"
)

func main() {

     t2 := time.Now()

     year, _, _ := t2.Date()
     t1 := time.Date(year, 0, 0, 0, 0, 0, 0, time.Local)

     elapsed := time.Since(t1)

     fmt.Println(elapsed)
}

Since 函数返回自指定日期时间以来经过的时间。它是 time.Now().Sub(t) 的简写。

$ go run main.go
4336h53m3.593593645s

Go 日期时间 位置

Go 中的 In 函数将时间值转换为特定位置。这对于处理时区和确保日期时间值在所需上下文中显示特别有用。

在示例中,我们检索当前的本地时间,并使用 In 函数将其转换为各种时区。这展示了如何有效地处理时区转换。

main.go
package main

import (
     "fmt"
     "log"
     "time"
)

func main() {

     names := []string{
          "Local",
          "UTC",
          "Pacific/Galapagos",
          "Europe/Budapest",
          "Europe/Moscow",
          "Asia/Vladivostok",
          "Antarctica/Vostok",
          "America/New_York",
          "Africa/Tripoli",
     }

     now := time.Now()

     for _, name := range names {

          loc, err := time.LoadLocation(name)

          if err != nil {
               log.Fatal(err)
          }

          t := now.In(loc)

          fmt.Println(loc, ": ", t)
     }
}

该示例获取当前的本地时间,并确定不同位置的相应时间。

$ go run main.go
Local :  2022-05-29 17:53:24.652877602 +0200 CEST
UTC :  2022-05-29 15:53:24.652877602 +0000 UTC
Pacific/Galapagos :  2022-05-29 09:53:24.652877602 -0600 -06
Europe/Budapest :  2022-05-29 17:53:24.652877602 +0200 CEST
Europe/Moscow :  2022-05-29 18:53:24.652877602 +0300 MSK
Asia/Vladivostok :  2022-05-30 01:53:24.652877602 +1000 +10
Antarctica/Vostok :  2022-05-29 21:53:24.652877602 +0600 +06
America/New_York :  2022-05-29 11:53:24.652877602 -0400 EDT
Africa/Tripoli :  2022-05-29 17:53:24.652877602 +0200 EET

Go Unix 时间

Unix 时间,也称为 POSIX 时间,表示自 Unix 纪元(1970 年 1 月 1 日 00:00:00 UTC)以来经过的秒数。它是计算中广泛使用的时间表示标准。

main.go
package main

import (
     "fmt"
     "time"
)

func main() {

     timestamp := time.Now().Unix()
     fmt.Printf("%d\n", timestamp)
}

在示例中,我们使用 Unix 函数检索当前的 Unix 时间。此值可用于时间戳或跨系统同步事件。

$ go run main.go
1653839627

Go 日期时间 比较

要在 Go 中比较日期时间值,我们使用 EqualBeforeAfter 函数。这些函数能够对时间点进行精确比较。

main.go
package main

import (
     "fmt"
     "time"
)

func main() {

     var t1 = time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
     var t2 = time.Date(2021, time.July, 28, 16, 22, 0, 0, time.UTC)
     var t3 = time.Date(2021, time.July, 28, 16, 22, 0, 0, time.UTC)

     if t1.Equal(t2) {

          fmt.Println("t1 and t2 are equal")
     } else {

          fmt.Println("t1 and t2 are not equal")
     }

     if t2.Equal(t3) {

          fmt.Println("t2 and t3 are equal")
     } else {

          fmt.Println("t2 and t3 are not equal")
     }

     if t1.Before(t2) {

          fmt.Println("t1 is before t2")
     }

     if t3.After(t1) {

          fmt.Println("t3 is after t1")
     }
}

在示例中,我们比较了三个日期时间值,以确定它们的相等性和相对顺序。这展示了比较函数在处理日期时间逻辑中的实用性。

$ go run main.go
t1 and t2 are not equal
t2 and t3 are equal
t1 is before t2
t3 is after t1

来源

Go time 包 - 参考

在本文中,我们探讨了在 Go 中处理日期和时间的各种方法,包括检索当前时间、格式化、解析、执行算术以及处理时区。这些示例展示了 Go 的 time 包在有效管理日期时间操作方面的多功能性和强大功能。

作者

我叫 Jan Bodnar,我是一名充满热情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。至今,我已撰写了 1400 多篇文章和 8 本电子书。我在教授编程方面拥有十多年的经验。

列出所有 Go 教程