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

相关推荐
JaguarJack5 分钟前
为什么 PHP 闭包要加 static?
后端·php·服务端
BingoGo15 分钟前
为什么 PHP 闭包要加 static?
后端
是糖糖啊35 分钟前
OpenClaw 从零到一实战指南(飞书接入)
前端·人工智能·后端
百度Geek说40 分钟前
基于Spark的配置化离线反作弊系统
后端
Java编程爱好者1 小时前
虚拟线程深度解析:轻量并发编程的未来趋势
后端
苏三说技术1 小时前
Spring AI 和 LangChain4j ,哪个更好?
后端
Soofjan2 小时前
(二)数组和切片
后端
Java不加班2 小时前
Nginx 核心实战指南:反向代理、负载均衡与动静分离
后端
子玖2 小时前
微信扫码注册登录-基于网站应用
后端·微信·go