Go 语言的 time 包提供了丰富的时间处理功能,包括时间的获取、格式化、解析、计算等操作。本文将详细介绍 time 包的核心功能和使用方法。
1. 基本时间类型
time.Time
time.Time 是表示时间点的核心结构体,包含年月日、时分秒、纳秒和时区信息。
Go
package main
import (
"fmt"
"time"
)
func main() {
// 获取当前时间
now := time.Now()
fmt.Println("当前时间:", now)
// 创建特定时间
specificTime := time.Date(2023, time.December, 25, 10, 30, 0, 0, time.UTC)
fmt.Println("特定时间:", specificTime)
}
time.Duration
time.Duration 表示时间间隔,以纳秒为单位。
Go
func main() {
// 定义时间间隔
var duration time.Duration = 2 * time.Hour + 30 * time.Minute
fmt.Println("时间间隔:", duration)
fmt.Println("小时数:", duration.Hours())
fmt.Println("分钟数:", duration.Minutes())
fmt.Println("秒数:", duration.Seconds())
}
2. 时间获取
Go
func main() {
now := time.Now()
// 获取时间的各个组成部分
fmt.Println("年:", now.Year())
fmt.Println("月:", now.Month()) // 返回 time.Month 类型
fmt.Println("日:", now.Day())
fmt.Println("时:", now.Hour())
fmt.Println("分:", now.Minute())
fmt.Println("秒:", now.Second())
fmt.Println("纳秒:", now.Nanosecond())
fmt.Println("星期:", now.Weekday()) // 返回 time.Weekday 类型
fmt.Println("一年中的第几天:", now.YearDay())
// 获取时间戳
fmt.Println("Unix 时间戳:", now.Unix()) // 秒
fmt.Println("Unix 毫秒:", now.UnixMilli()) // 毫秒
fmt.Println("Unix 微秒:", now.UnixMicro()) // 微秒
fmt.Println("Unix 纳秒:", now.UnixNano()) // 纳秒
}
3. 时间格式化与解析
格式化输出
Go 使用特定的参考时间进行格式化:Mon Jan 2 15:04:05 MST 2006
Go
func main() {
now := time.Now()
// 常用格式化模式
fmt.Println("RFC3339:", now.Format(time.RFC3339))
fmt.Println("自定义格式 1:", now.Format("2006-01-02 15:04:05"))
fmt.Println("自定义格式 2:", now.Format("2006/01/02"))
fmt.Println("自定义格式 3:", now.Format("15:04:05"))
fmt.Println("自定义格式 4:", now.Format("2006年01月02日 15时04分05秒"))
// 预定义格式常量
fmt.Println("ANSIC:", now.Format(time.ANSIC))
fmt.Println("UnixDate:", now.Format(time.UnixDate))
fmt.Println("RubyDate:", now.Format(time.RubyDate))
}
时间解析
Go
func main() {
// 解析时间字符串
timeStr := "2023-12-25 10:30:00"
// 方式1:使用固定格式解析
t1, err := time.Parse("2006-01-02 15:04:05", timeStr)
if err != nil {
panic(err)
}
fmt.Println("解析结果1:", t1)
// 方式2:使用预定义格式解析
t2, err := time.Parse(time.RFC3339, "2023-12-25T10:30:00Z")
if err != nil {
panic(err)
}
fmt.Println("解析结果2:", t2)
// 带时区解析
t3, err := time.ParseInLocation("2006-01-02 15:04:05", timeStr, time.Local)
if err != nil {
panic(err)
}
fmt.Println("带时区解析:", t3)
}
4. 时间计算与比较
时间计算
Go
func main() {
now := time.Now()
// 时间加减
afterOneHour := now.Add(time.Hour)
beforeOneDay := now.Add(-24 * time.Hour)
afterOneWeek := now.Add(7 * 24 * time.Hour)
fmt.Println("现在:", now)
fmt.Println("1小时后:", afterOneHour)
fmt.Println("1天前:", beforeOneDay)
fmt.Println("1周后:", afterOneWeek)
// 使用 AddDate 进行日期加减
nextYear := now.AddDate(1, 0, 0) // 加1年
nextMonth := now.AddDate(0, 1, 0) // 加1个月
nextWeek := now.AddDate(0, 0, 7) // 加7天
fmt.Println("1年后:", nextYear)
fmt.Println("1月后:", nextMonth)
fmt.Println("1周后:", nextWeek)
}
时间比较
Go
func main() {
t1 := time.Now()
t2 := t1.Add(time.Hour)
// 时间比较
fmt.Println("t1 在 t2 之前:", t1.Before(t2))
fmt.Println("t1 在 t2 之后:", t1.After(t2))
fmt.Println("t1 等于 t2:", t1.Equal(t2))
// 计算时间差
diff := t2.Sub(t1)
fmt.Println("时间差:", diff)
fmt.Println("小时差:", diff.Hours())
fmt.Println("分钟差:", diff.Minutes())
}
5. 定时器与休眠
定时器操作
Go
func main() {
// 一次性定时器
timer := time.NewTimer(2 * time.Second)
<-timer.C
fmt.Println("2秒时间到!")
// 停止定时器(如果还没触发)
timer2 := time.NewTimer(5 * time.Second)
go func() {
<-timer2.C
fmt.Println("定时器触发")
}()
time.Sleep(2 * time.Second)
stopped := timer2.Stop()
if stopped {
fmt.Println("定时器已停止")
}
// 简单的休眠
fmt.Println("开始休眠...")
time.Sleep(3 * time.Second)
fmt.Println("休眠结束!")
}
Ticker(周期定时器)
Go
func main() {
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
done := make(chan bool)
go func() {
time.Sleep(5 * time.Second)
done <- true
}()
for {
select {
case <-done:
fmt.Println("完成!")
return
case t := <-ticker.C:
fmt.Println("Tick at", t.Format("15:04:05"))
}
}
}
6. 时区处理
Go
func main() {
// 获取本地时间
localTime := time.Now()
fmt.Println("本地时间:", localTime)
// 转换为 UTC 时间
utcTime := localTime.UTC()
fmt.Println("UTC 时间:", utcTime)
// 加载特定时区
location, err := time.LoadLocation("America/New_York")
if err != nil {
panic(err)
}
// 转换为纽约时间
nyTime := localTime.In(location)
fmt.Println("纽约时间:", nyTime)
// 创建特定时区的时间
customTime := time.Date(2023, 12, 25, 10, 0, 0, 0, location)
fmt.Println("自定义时区时间:", customTime)
}
7. 实用函数示例
计算程序执行时间
Go
func main() {
start := time.Now()
// 模拟耗时操作
time.Sleep(2 * time.Second)
elapsed := time.Since(start)
fmt.Printf("程序执行耗时: %v\n", elapsed)
fmt.Printf("程序执行耗时(毫秒): %d ms\n", elapsed.Milliseconds())
}
时间区间判断
Go
func isBusinessHours(t time.Time) bool {
hour := t.Hour()
return hour >= 9 && hour < 18
}
func main() {
testTime := time.Date(2023, 12, 25, 14, 30, 0, 0, time.Local)
if isBusinessHours(testTime) {
fmt.Println("在营业时间内")
} else {
fmt.Println("非营业时间")
}
}
生成时间序列
Go
func main() {
start := time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)
// 生成一周的时间序列
for i := 0; i < 7; i++ {
current := start.AddDate(0, 0, i)
fmt.Println(current.Format("2006-01-02 Monday"))
}
}
8. 最佳实践
-
始终处理时区:在涉及多时区的应用中,明确指定时区
-
使用 time.Duration:避免直接使用数字表示时间间隔
-
及时停止定时器:防止 goroutine 泄漏
-
错误处理:始终检查时间解析等操作的错误
Go
func safeParseTime(timeStr string) (time.Time, error) {
layouts := []string{
time.RFC3339,
"2006-01-02 15:04:05",
"2006/01/02",
time.ANSIC,
}
for _, layout := range layouts {
if t, err := time.Parse(layout, timeStr); err == nil {
return t, nil
}
}
return time.Time{}, fmt.Errorf("无法解析时间字符串: %s", timeStr)
}
time 包是 Go 语言中功能强大且设计良好的包之一,熟练掌握它的使用对于开发可靠的应用程序至关重要。