位置:首页 > Go > Go 语言 time 包怎么用?时间格式化与时间戳转换详解

Go 语言 time 包怎么用?时间格式化与时间戳转换详解

时间:2026-08-25  |  作者:云端旅人  |  阅读:0

目录

  1. time 包能解决哪些时间问题
  2. 时间戳怎么获取,怎么转回时间对象
  3. 时间间隔与常见时间运算
  4. 时间格式化与字符串解析的关键规则
  5. 日常开发里该怎么选这些 API

前言

Go 里的时间处理看起来常见,真正写到格式化、时间戳互转和时区解析时却很容易出错,尤其是 `2006-01-02 15:04:05` 这套模板规则。下面按开发里最常见的几类任务重新整理 `time` 包用法,并结合原始示例说明每组 API 该在什么场景下使用。

time 包能解决哪些时间问题

在 Go 里,只要涉及当前时间、时间差、定时等待、日志时间展示,基本都会用到 time 包。它既负责表示时间点,也提供时间戳转换、时间运算、格式化输出和字符串解析等能力,是处理时间相关逻辑的基础工具。

time.Time 是最核心的时间类型。通常先通过 time.Now() 获取当前时间对象,再从中读取年、月、日、时、分、秒等字段。

package main

import (
	"fmt"
	"time"
)

func main() {

	// 获取当前时间 2022-07-19 10:03:42.70981 +0800 CST m=+0.000080935
	now := time.Now()
	fmt.Println(now)

	fmt.Println(now.Year())
	fmt.Println(now.Month())
	fmt.Println(now.Day())
	fmt.Println(now.Hour())
	fmt.Println(now.Minute())
	fmt.Println(now.Second())

}

如果你的需求只是“拿到当前时间并拆出具体字段”,这一组方法就已经足够。后续的时间戳、格式化和加减运算,本质上也都是围绕 time.Time 展开的。

时间戳怎么获取,怎么转回时间对象

时间戳通常指从 1970 年 1 月 1 日(UTC)开始累计到当前时刻的时间值。实际开发里常见的有秒、毫秒和纳秒三种粒度。Go 里可以直接从时间对象上读取:

Go time 包时间戳与时间对象互转流程图
时间戳与 time.Time 转换关系用结构化流程展示当前时间、不同精度时间戳以及 time.Unix() 之间的转换关系。
package main

import (
	"fmt"
	"time"
)

func main() {

	// 获取当前时间 2022-07-19 10:03:42.70981 +0800 CST m=+0.000080935
	now := time.Now()
	fmt.Println(now)

	// 时间戳 秒
	fmt.Println(now.Unix())

	// 时间戳 毫秒
	fmt.Println(now.UnixMilli())

	// 时间戳 纳秒
	fmt.Println(now.UnixNano())

}

这几个方法分别对应不同精度。接口对接、数据库存储、消息队列或前后端传值时,先确认对方使用的是秒、毫秒还是纳秒,避免精度错位。

如果拿到的是 Unix 时间戳,想恢复成 time.Time,可以使用 time.Unix()

package main

import (
	"fmt"
	"time"
)

func main() {

	// 获取当前时间 2022-07-19 10:03:42.70981 +0800 CST m=+0.000080935
	now := time.Now()
	fmt.Println(now)
	
	// 时间戳转时间类型
	unix := time.Unix(now.Unix(), 0)
	fmt.Println(unix)

}

这里的第一个参数是秒级时间戳,第二个参数是纳秒部分。示例里传入 0,表示只按秒恢复。如果你手里是更高精度的数据,需要把秒和纳秒拆开再传入。

时间间隔与常见时间运算

表示“经过了多久”时,Go 使用的是 time.Duration。它的底层单位是纳秒,适合描述两个时间点之间的间隔,也适合做延迟、超时和时间加减。

Go time 包时间运算与 Duration 关系图
Duration 与时间运算速览把 Duration 单位、Add/Sub/AddDate 以及 Since/Until。

time 包预定义了常见时间单位常量:

const (
    Nanosecond  Duration = 1
    Microsecond          = 1000 * Nanosecond
    Millisecond          = 1000 * Microsecond
    Second               = 1000 * Millisecond
    Minute               = 60 * Second
    Hour                 = 60 * Minute
)

这也是为什么我们经常会写出 time.Second * 5time.Minute * 15 这样的表达式。它可读性强,也适合直接传给等待、超时和加减时间的相关 API。

time.Duration 还提供了不同粒度的读取方法:

func (d Duration) Nanoseconds() int64 {}   // 纳秒
func (d Duration) Microseconds() int64 {}  // 微秒
func (d Duration) Milliseconds() int64 {}  // 毫秒
func (d Duration) Seconds() float64 {}     // 秒
func (d Duration) Minutes() float64 {}     // 分钟
func (d Duration) Hours() float64 {}       // 小时

如果已经有一个时间点,最常见的操作就是做加减和求差值。Go 提供了几组常用方法:

func (t Time) Add(d Duration) Time {}
func (t Time) Sub(u Time) Duration {}
func (t Time) AddDate(years int, months int, days int) Time {}

Add 用于按时间间隔做加减,Sub 用于计算两个时间点之间的差值,AddDate 则适合按年、月、日进行偏移。对于“距离现在过去了多久”或“离某个时间点还有多久”这类场景,还可以直接使用快捷函数:

func Since(t Time) Duration {}
func Until(t Time) Duration {}

其中,Since 等价于 time.Now().Sub(t)Until 等价于 t.Sub(time.Now())。写计时、倒计时或过期判断时,这两个函数通常会更顺手。

时间加减与差值计算示例

 t := time.Now()
 fmt.Println(t)                      // 2022-07-17 22:41:06.001567 +0800 CST m=+0.000057466

 //时间增加 1小时
 fmt.Println(t.Add(time.Hour * 1))   // 2022-07-17 23:41:06.001567 +0800 CST m=+3600.000057466
 //时间增加 15 分钟
 fmt.Println(t.Add(time.Minute * 15))// 2022-07-17 22:56:06.001567 +0800 CST m=+900.000057466
 //时间增加 10 秒钟
 fmt.Println(t.Add(time.Second * 10))// 2022-07-17 22:41:16.001567 +0800 CST m=+10.000057466

 //时间减少 1 小时
 fmt.Println(t.Add(-time.Hour * 1))  // 2022-07-17 21:41:06.001567 +0800 CST m=-3599.999942534
 //时间减少 15 分钟
 fmt.Println(t.Add(-time.Minute * 15))// 2022-07-17 22:26:06.001567 +0800 CST m=-899.999942534
 //时间减少 10 秒钟
 fmt.Println(t.Add(-time.Second * 10))// 2022-07-17 22:40:56.001567 +0800 CST m=-9.999942534

 time.Sleep(time.Second * 5)
 t2 := time.Now()
 // 计算 t 到 t2 的持续时间
 fmt.Println(t2.Sub(t))              // 5.004318874s
 // 1 年之后的时间
 t3 := t2.AddDate(1, 0, 0)
 // 计算从 t 到当前的持续时间
 fmt.Println(time.Since(t))          // 5.004442316s
 // 计算现在到明年的持续时间
 fmt.Println(time.Until(t3))         // 8759h59m59.999864s

这段代码基本覆盖了开发里最常见的三类需求:给时间点做偏移、比较两个时间点的差值、基于当前时刻做耗时和剩余时间计算。实际写业务逻辑时,优先区分你处理的是“时间点”还是“时间间隔”,代码会更清晰。

Go 时间格式化与解析模板规则图
格式化模板与时区解析用对照式信息图总结 Go 特有的时间模板写法,以及 24 小时制、12。

时间格式化与字符串解析的关键规则

时间格式化是 time 包里最容易踩坑、也是使用最频繁的一部分。Go 没有采用常见的 Y-m-d H:M:S 这类占位符,而是用一个固定参考时间作为模板:

2006-01-02 15:04:05

准确地说,Go 使用的是 2006 年 1 月 2 日 15 点 04 分 05 秒这个参考时间来表示格式。如果模板写错,即使看起来像“正常日期格式”,结果也可能不符合预期。

格式化输出示例如下:

    now := time.Now()
    // 格式化的模板为Go的出生时间2006年1月2号15点04分 Mon Jan
    // 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"))
    fmt.Println(now.Format("2006/01/02 15:04"))
    fmt.Println(now.Format("15:04 2006/01/02"))
    fmt.Println(now.Format("2006/01/02"))

这里有一个容易忽略的点:如果你要输出 12 小时制,模板里要明确写上 PM。如果使用 24 小时制,则通常用 15 来表示小时部分。

反过来,如果你需要把字符串解析成 time.Time,可以使用 ParseParseInLocation。当输入字符串本身没有完整时区信息,但业务又依赖指定地区时间时,推荐直接使用后者:

now := time.Now()
fmt.Println(now)
// 加载时区
loc, err := time.LoadLocation("Asia/Shanghai")
if err != nil {
    fmt.Println(err)
    return
}
// 按照指定时区和指定格式解析字符串时间
timeObj, err := time.ParseInLocation("2006/01/02 15:04:05", "2019/08/04 14:15:20", loc)
if err != nil {
    fmt.Println(err)
    return
}
fmt.Println(timeObj)
fmt.Println(timeObj.Sub(now))

time.LoadLocation("Asia/Shanghai") 先加载时区,再配合 time.ParseInLocation 按指定模板解析字符串。这样做的好处是,解析结果会直接落在目标时区,适合处理本地业务时间、日志对齐、报表统计等需求。

日常开发里该怎么选这些 API

如果只是获取当前时间并读取字段,用 time.Now() 加上 Year()Month()Day() 这类方法就够了;如果需要跨系统传值,优先确认时间戳单位,再选择 Unix()UnixMilli()UnixNano()

需要做时间差、超时或延迟时,核心是 time.Duration;需要对某个时间点做前后偏移,用 AddAddDate;需要“距离现在多久”,直接用 SinceUntil 更简洁。

而在格式化与解析场景里,最值得记住的一条规则就是 Go 的模板时间:2006-01-02 15:04:05。把这个参考模板记熟,再配合时区处理,绝大多数时间相关需求都能比较稳地落地。

免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。

相关文章

更多

精选合集

更多

大家都在玩

热门话题

大家都在看

更多