Time
作者: ryan 发布于: 2025/11/14 更新于: 2025/11/14 字数: 0 字 阅读: 0 分钟
在Go语言中,time包的核心类型是time.Time,它是一个结构体,用于表示一个具体的时间点。
time.Time的定义位于Go标准库的time包中,源码(src/time/time.go)中大致如下:
type Time struct {
wall uint64 // 墙上时间(wall time)相关信息
ext int64 // 扩展时间(通常是Unix时间戳的纳秒数)
loc *Location // 时区信息
}wall和ext:这两个字段共同存储时间信息。wall用于表示本地时间(墙上时间),而ext存储绝对时间(通常基于1970-01-01 00:00:00 UTC的纳秒数)。
loc指向一个time.Location类型的指针,表示时间的时区信息。如果loc为nil,时间被视为UTC。
时间的格式化
Go的格式化方式与许多其他语言不同,它使用参考时间(2006-01-02 15:04:05 -0700 MST)作为格式模板,而不是传统的格式化占位符(如%Y、%m)。
2006-01-02表示YYYY-MM-DD(如2025-11-13)15:04:05表示HH:MM:SS(24小时制)。PM表示12小时制上下午标记。-0700表示时区偏移量。
package main
import (
"fmt"
"time"
)
func main() {
t := time.Now()
fmt.Printf("%T %#[1]v\n", t)
fmt.Printf("%T %[1]v\n", t)
fmt.Printf("%T %[1]v\n", t.UTC()) //GMT
}time.Time time.Date(2025, time.November, 13, 11, 7, 43, 350282500, time.Local)
time.Time 2025-11-13 11:07:43.3502825 +0800 CST m=+0.000000001
time.Time 2025-11-13 03:07:43.3502825 +0000 UTC格式化常量
年(Year)
常量:
2006:完整四位年份(如2025)06:两位年份(如25)
用法:
2006用于需要完整年份的场景(如2025-11-13)
06用于简洁表示(如25/11/13)。
月(Month)
常量:
Jan:短名称(如Nov)。January:完整名称(如November)。01:两位数字,补零(如11)。1:数字,不补零(如11)。
用法:
Jan/January用于人类可读的输出。01/1用于数字格式,01确保两位(如01表示1月)。
fmt.Println(t.Format("Jan")) // 输出:Nov
fmt.Println(t.Format("January")) // 输出:November
fmt.Println(t.Format("01")) // 输出:11
fmt.Println(t.Format("1")) // 输出:11星期(Day of the Week)
常量:
Mon:短名称(如Thu)。- "Monday":完整名称(如Thursday)。
用法:
用于显示星期几,常见于日志或日历。
fmt.Println(t.Format("Mon")) // 输出:Thu
fmt.Println(t.Format("Monday")) // 输出:Thursday日(Day of the Month)
常量:
2:不补零(如13)。_2:补空格(如2表示2日)。02:补零(如02表示2日)。
用法:
2:简洁,适合不要求对齐的场景。_2:补空格,适合固定宽度的输出(如表格)。02:补零,适合标准日期格式(如2025-11-13)。
fmt.Println(t.Format("2")) // 输出:13
fmt.Println(t.Format("_2")) // 输出:13(前面无空格)
fmt.Println(t.Format("02")) // 输出:13
fmt.Println(t.Format("_2")) // 对于2日,输出: 2年中日(Day of the Year)
常量:
__2:补空格(如317或2)。002:补零(如317或002)。
用法:
- 表示一年中的第几天(1-366),常用于科学计算或特定日期分析。
fmt.Println(t.Format("002")) // 输出:317(11月13日是2025年的第317天)
fmt.Println(t.Format("__2")) // 输出:317小时(Hour)
常量:
15:24小时制(如13)。3:12小时制(如1)。03:12小时制,补零(如01)。
用法:
15:标准24小时制,适合精确时间。3/03:12小时制,需配合PM表示上午/下午。
fmt.Println(t.Format("15")) // 输出:13(下午1点)
fmt.Println(t.Format("3")) // 输出:1
fmt.Println(t.Format("03")) // 输出:01分钟(Minute)
常量:
4:不补零(如4)。04:补零(如04)。
用法:
- 表示分钟,
04确保两位输出。
fmt.Println(t.Format("4")) // 输出:58
fmt.Println(t.Format("04")) // 输出:58秒(Second)
常量:
5:不补零(如5)。05:补零(如05)。
用法:表示秒,05适合标准时间格式。
fmt.Println(t.Format("5")) // 输出:0(假设无秒)
fmt.Println(t.Format("05")) // 输出:00上午/下午(AM/PM Mark)
常量:
PM:显示AM或PM。
用法:
与12小时制(3/03)配合使用,表示上午或下午。
fmt.Println(t.Format("3:04 PM")) // 输出:1:58 PM时区(Timezone)
常量:
-0700:偏移量,格式为±hhmm(如+0800)。MST:时区名称(如HKT、UTC)。Z0700:RFC3339格式,UTC为Z,否则±hhmm。
用法:
-0700:显示数字偏移,适合标准时间表示。MST:显示时区名称,可能因系统或时区不同而变化。
fmt.Println(t.Format("-0700")) // 输出:+0800
fmt.Println(t.Format("MST")) // 输出:HKT小数部分(Fractional Seconds)
常量:
0或9:表示秒的小数部分(纳秒)。- 区别:
0:超出指定位数补零(如.0000)。9:超出指定位数截断,不补零(如.1234)。
用法:
用于高精度时间,位数由0或9的个数决定(1-9位)。
fmt.Println(t.Format("05.0000")) // 输出:00.1234(补零到4位)
fmt.Println(t.Format("05.9999")) // 输出:00.1234(截断到实际位数)示例
package main
import (
"fmt"
"time"
)
func main() {
t := time.Now()
fmt.Printf("%T %#[1]v \n", t)
fmt.Printf("%T %[1]v\n", t)
fmt.Printf("%T %[1]v\n", t.UTC()) //GMT
fmt.Println(t.Format("2006-01-02 15:04:05 -0700")) //时间格式化字符串
// "01 02 3 04 05 06 -0700" 月 日 12小时制 分 秒 年 PM 美国西海海岸西七区
fmt.Println(t.Format("2006-01-02 03:04:05 PM -0700"))
fmt.Println(t.Format("2006-01-02 3:04 PM"))
}输出
time.Time time.Date(2025, time.November, 13, 17, 7, 41, 482211600, time.Local)
time.Time 2025-11-13 17:07:41.4822116 +0800 CST m=+0.000000001
time.Time 2025-11-13 09:07:41.4822116 +0000 UTC
2025-11-13 17:07:41 +0800
2025-11-13 05:07:41 PM +0800
2025-11-13 5:07 PM解析
%T输出变量的类型,这里是time.Time。%#[1]v使用 Go 语法表示的详细值(包括字段),time.Now()返回当前时间,格式为time.Date(年, 月, 日, 时, 分, 秒, 纳秒, 时区)。t.UTC()将时间转换为 UTC(格林尼治时间,+0000)。因为本地时间是 +0800(比 UTC 早 8 小时),所以 17:02:59 转换为 UTC 后是 09:02:59。t.Format使用指定的格式化字符串来格式化时间。- Go 的时间格式化使用 参考时间
2006-01-02 15:04:05 -0700(这是 Go 的一个固定时间点)。 - 格式字符串
2006-01-02 03 PM:04:05 -0700表示12 小时制的小时(1-12)。PM显示 AM/PM 标志。其他部分与上一行类似。
时间解析
将 time.Time 转换为字符串 Format
Format 方法的 layout 参数是一个模板字符串,必须基于 Go 的参考时间:Mon Jan 2 15:04:05 MST 2006(即 2006-01-02 15:04:05)。
2006年01/02 15:04:05.000000000 -0700:表示年、月、日、时、分、秒、纳秒和时区。2006-01-02 15:04:05.999999999 -0700:使用连字符分隔,显示完整的纳秒。
t := time.Now()
fmt.Printf("%T %[1]v\n", t.UTC())
//t.UTC() 将时间转换为 UTC 时区,影响输出中的时间和时区部分。
fmt.Println(t.Format("2006年01/02 15:04:05.000000000 -0700")) //时间格式化字符串
fmt.Println(t.Format("2006年01/02 15:04:05.999999999 -0700")) //时间格式化字符串
fmt.Println(t.UTC().Format("2006-01-02 15:04:05.999999999 -0700"))
fmt.Println(t.UTC().Format("2006-01-02 15:04:05.000000000 -0700"))
//.000000000 表示纳秒,.999999999 效果相同(Go 会填充或截断)。
//layout 中的时区部分(-0700)决定了时区格式,+0800 或 +0000 会根据实际时间动态调整。将字符串解析为 time.Time
使用time.Parse(layout, value) 将字符串解析为 time.Time 类型。
// 时间字符串 -> Time 类型
timestr := "2025-11/14 15:51:49.663491700 +0800"
//layout 以匹配 timestr 的格式
t1, err := time.Parse("2006-01/02 15:04:05.999999999 -0700", timestr)
if err != nil {
panic(err)
} else {
fmt.Println(t1)
}时间差
package main
import (
"fmt"
"time"
)
// 解析成时间实例才能计算
func main() {
// 获取当前时间实例
t := time.Now()
// 打印提示信息
fmt.Println("时间实例才能计算")
// 获取时间的年、月、日等信息
// t.Year() 返回年份(如 2025)
// t.Month() 返回月份(time.Month 类型,如 November)
// int(t.Month()) 将月份转换为整数(1=January, 11=November)
// t.Day() 返回日期(当月第几天,如 14)
fmt.Println(
t.Year(), t.Month(), int(t.Month()), t.Day(),
)
// 打印提示信息
fmt.Println("取今年过去了多少天")
// t.YearDay() 返回今年已经过去的总天数(从 1 月 1 日开始计数)
fmt.Println(t.YearDay())
// 获取时间的时、分、秒、纳秒等信息
// t.Hour() 返回小时(24 小时制,如 16)
// t.Minute() 返回分钟(如 27)
// t.Second() 返回秒(如 45)
// t.Nanosecond() 返回纳秒(0 到 999999999)
fmt.Println(t.Hour(), t.Minute(), t.Second(), t.Nanosecond())
// 获取星期信息
// t.Weekday() 返回星期(time.Weekday 类型,如 time.Friday)
// t.Weekday().String() 返回星期名称(字符串,如 "Friday")
// int(t.Weekday()) 返回星期对应的整数(0=Sunday, 5=Friday)
fmt.Println(t.Weekday(), t.Weekday().String(), int(t.Weekday()))
// 打印提示信息
fmt.Println("取今年过去了多少周")
// t.ISOWeek() 返回年份和该年第几周(ISO 8601 标准)
// 返回两个值:年份和周数(如 2025, 46)
fmt.Println(t.ISOWeek())
// 打印提示信息
fmt.Println("时间戳")
// 时间戳是从 1970 年 1 月 1 日 00:00:00 UTC 到现在的秒数
// t.Unix() 返回秒级时间戳(如 1763262465)
fmt.Println(t.Unix())
// 比较不同精度的时间戳
// t.UnixNano() 返回纳秒级时间戳(秒 * 1e9 + 纳秒)
// 注意:UnixNano 在 2038 年后可能溢出,需谨慎使用
fmt.Println(t.Unix(), t.UnixNano())
// 打印秒、微秒、纳秒时间戳
// t.UnixMicro() 返回微秒级时间戳(秒 * 1e6 + 微秒)
fmt.Println(t.Unix(), t.UnixMicro(), t.UnixNano())
// 打印秒、微秒、纳秒、毫秒时间戳
// t.UnixMilli() 返回毫秒级时间戳(秒 * 1e3 + 毫秒)
// 毫秒时间戳在 JavaScript 中常用
fmt.Println(t.Unix(), t.UnixMicro(), t.UnixNano(), t.UnixMilli())
// 注释说明不同时间单位:
// 微秒 (micro): 1 秒 = 1,000,000 微秒
// 纳秒 (nano): 1 秒 = 1,000,000,000 纳秒
// 毫秒 (milli): 1 秒 = 1,000 毫秒
// JavaScript 中通常使用毫秒时间戳
}输出
时间实例才能计算
2025 November 11 14
取今年过去了多少天
318
16 28 2 756130800
Friday Friday 5
取今年过去了多少周
2025 46
时间戳
1763108882
1763108882 1763108882756130800
1763108882 1763108882756130 1763108882756130800
1763108882 1763108882756130 1763108882756130800 1763108882756时间实例:
time.Now()创建一个当前时间的time.Time实例,包含日期、时间和时区信息。time.Time提供了丰富的字段访问方法(如Year(), Month(), Day())。
日期与时间:
t.Year()、t.Month()等方法提取日期的组成部分。int(t.Month())将time.Month转换为整数(1 到 12)。t.YearDay()返回当年的天数(1 到 365/366)。
时间戳:
t.Unix()返回秒级时间戳(Unix Epoch 至今的秒数)。t.UnixMilli()、t.UnixMicro()、t.UnixNano()分别返回毫秒、微秒、纳秒级时间戳。- 纳秒时间戳(
UnixNano)在 2038 年后可能溢出,需注意。
星期与周数:
t.Weekday()返回星期,int(t.Weekday())转换为整数(0=周日,6=周六)。t.ISOWeek()返回 ISO 8601 标准的年份和周数(周一为每周第一天)
时区
时区的基本概念
什么是时区?
时区是将地球表面划分为为24个主要时区,每个时区覆盖约15°经度,时间相差1小时。区域使用统一的标准时间。以格林尼治标准时间(UTC)为基准,东、西方向的时区分别以+或-表示。北京位于UTC+8。
为什么要这样做?
不同地区因地球自转有时间差异,使用时区确保时间协调统一时间表示。
偏移量
时区的偏移量以小时和分钟表示,正偏移表示早于UTC(东区),负偏移表示晚于UTC(西区)。
例如:北京时间(CST):+0800(比UTC早8小时)。 纽约时间(EST):-0500(比UTC晚5小时)。
package main
import (
"fmt"
"time"
)
func main() {
// 加载 Asia/Shanghai 时区
loc, err := time.LoadLocation("Asia/Shanghai")
if err != nil {
fmt.Printf("加载时区失败: %v\n", err)
return
}
// 定义时间字符串
timestr1 := "2025/11/14 16:34:54"
// 在指定时区解析时间字符串为 time.Time
t1, err := time.ParseInLocation("2006/01/02 15:04:05", timestr1, loc)
if err != nil {
fmt.Printf("解析时间失败: %v\n", err)
return
}
// 打印解析后的时间
fmt.Println(t1)
// 打印转换为本地时区的时间
fmt.Println(t1.Local())
}t1.Local()返回的时间取决于运行环境的本地时区。例如:
- 如果程序运行在 Asia/Shanghai 系统上,
t1.Local()和t1相同(都是 +0800)。 - 如果运行在 UTC 系统上,
t1.Local()会显示 UTC 时间(-8 小时)。
time.LoadLocation 加载指定时区(这里是 Asia/Shanghai,即中国标准时间,CST,+0800)。并返回 *time.Location(时区对象)和 error(错误信息)。
time.ParseInLocation(layout, value, loc)将字符串解析为 time.Time 类型,并指定解析时的时区。
layout:时间格式模板,基于 Go 的参考时间2006-01-02 15:04:05 MST。value:要解析的时间字符串(timestr1)。loc:解析时使用的时区(Asia/Shanghai)。
时间运算
package main
import (
"fmt"
"time"
)
func main() {
// 加载 Asia/Shanghai 时区
loc, err := time.LoadLocation("Asia/Shanghai")
if err != nil {
fmt.Printf("加载时区失败: %v\n", err)
return
}
// 定义时间字符串
timestr1 := "2025/11/14 16:34:54"
// 解析时间字符串,修正 layout 去掉 .9
t1, err := time.ParseInLocation("2006/01/02 15:04:05", timestr1, loc)
if err != nil {
fmt.Printf("解析时间失败: %v\n", err)
return
}
// 打印解析后的时间和本地时间
fmt.Println("解析时间:", t1)
fmt.Println("本地时间:", t1.Local())
// 时间计算
fmt.Println("\n时间计算")
t2 := time.Now()
d := t2.Sub(t1) // 计算 t2 - t1 的时间差
// 修复格式化输出
fmt.Printf("时间差类型: %T, 值: %v\n", d, d)
fmt.Println("时间差(小时):", d.Hours())
fmt.Println("时间差(秒):", d.Seconds())
// 加三秒
fmt.Println("\n加三秒")
t3 := t1.Add(3 * time.Second)
fmt.Println("t1 + 3秒:", t3)
// 加三天
fmt.Println("\n加三天")
t4 := t1.Add(3 * 24 * time.Hour) // 3 天 = 3 * 24 小时
fmt.Println("t1 + 3天:", t4)
}输出
解析时间: 2025-11-14 16:34:54 +0800 CST
本地时间: 2025-11-14 16:34:54 +0800 CST
时间计算
时间差类型: time.Duration, 值: 13m29.1955599s
时间差(小时): 0.22477654441666667
时间差(秒): 809.1955599
加三秒
t1 + 3秒: 2025-11-14 16:34:57 +0800 CST
加三天
t1 + 3天: 2025-11-17 16:34:54 +0800 CST解析
t2.Sub(t1) 计算 t2 和 t1 的时间差,返回 time.Duration 类型,表示时间间隔。
d.Hours() 返回时间差的小时数(浮点数)。
d.Seconds() 返回时间差的秒数(浮点数)。
t1.Add(duration) 将 t1 加上指定的时间间隔3 * time.Second,返回新的 time.Time。
3 * time.Hour * 24 表示 3 天(3 × 24 小时)。t1.Add 将 t1 加上 3 天,返回新的 time.Time。
