Go 语言时间处理(time 包)详解

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. 最佳实践

  1. 始终处理时区:在涉及多时区的应用中,明确指定时区

  2. 使用 time.Duration:避免直接使用数字表示时间间隔

  3. 及时停止定时器:防止 goroutine 泄漏

  4. 错误处理:始终检查时间解析等操作的错误

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 语言中功能强大且设计良好的包之一,熟练掌握它的使用对于开发可靠的应用程序至关重要。

相关推荐
智商低情商凑36 分钟前
Go学习之 - Goroutines和channels
开发语言·学习·golang
编程点滴37 分钟前
Go 重试机制终极指南:基于 go-retry 打造可靠容错系统
开发语言·后端·golang
实心儿儿1 小时前
C++ —— 模板进阶
开发语言·c++
码事漫谈1 小时前
AI编程规模化实践:从1到100的工程化之道
后端
码事漫谈1 小时前
AI编程:更适合0到1的创意爆发,还是1到100的精雕细琢?
后端
码事漫谈1 小时前
Python与C#:从哲学到细节的全面对比
后端
码事漫谈1 小时前
Python与C++:从哲学到细节的全面对比
后端
萧鼎1 小时前
Python PyTesseract OCR :从基础到项目实战
开发语言·python·ocr
喵个咪2 小时前
基于 Go-Kratos 与 MCP 的推荐服务实战指南
后端·深度学习·微服务