XTime Guide - zhoudm1743/go-util GitHub Wiki

XTime 是 Go-Util 的核心时间处理工具,提供强大而直观的时间操作API,让日期时间处理变得简单而精确。

🚀 特性亮点

  • 🔗 链式调用: 流畅的方法链,提高代码可读性
  • 🌍 时区支持: 完整的时区处理和转换功能
  • 📅 格式化: 丰富的时间格式化选项
  • ⚡ 高性能: 优化的时间计算和缓存机制
  • 🎯 精确计算: 精确的时间差值和日期运算
  • 🔧 易扩展: 支持自定义格式和解析规则

📦 基础用法

创建 XTime 对象

import util "github.com/zhoudm1743/go-util"

// 当前时间
now := util.Now()                           // 当前时间
utcNow := util.NowUTC()                     // UTC当前时间

// 从时间戳创建
timestamp := util.FromTimestamp(1640995200) // 2022-01-01 00:00:00 UTC
milliTime := util.FromMillisecond(1640995200000)

// 从字符串解析
parsed := util.ParseTime("2023-01-01 15:30:00", "2006-01-02 15:04:05")
iso8601 := util.ParseISO8601("2023-01-01T15:30:00Z")
rfc3339 := util.ParseRFC3339("2023-01-01T15:30:00+08:00")

// 从日期构建
date := util.Date(2023, 1, 1, 15, 30, 0, 0)
dateUTC := util.DateUTC(2023, 1, 1, 15, 30, 0, 0)

// 从现有time.Time创建
t := time.Now()
xtime := util.TimeFrom(t)

基础信息获取

now := util.Now()

// 时间组件
fmt.Println(now.Year())         // 2023
fmt.Println(now.Month())        // 1
fmt.Println(now.Day())          // 15
fmt.Println(now.Hour())         // 14
fmt.Println(now.Minute())       // 30
fmt.Println(now.Second())       // 45
fmt.Println(now.Millisecond())  // 123
fmt.Println(now.Microsecond())  // 123456
fmt.Println(now.Nanosecond())   // 123456789

// 星期和年份信息
fmt.Println(now.Weekday())      // Monday
fmt.Println(now.WeekdayInt())   // 1 (周一为1)
fmt.Println(now.DayOfYear())    // 15
fmt.Println(now.WeekOfYear())   // 3

// 时间戳
fmt.Println(now.Timestamp())    // 1674657045
fmt.Println(now.TimestampMilli()) // 1674657045123
fmt.Println(now.TimestampMicro()) // 1674657045123456
fmt.Println(now.TimestampNano())  // 1674657045123456789

// 转换为原生time.Time
nativeTime := now.Time()

📅 时间格式化

预定义格式

now := util.Now()

// 常用格式
fmt.Println(now.Format())           // 2023-01-15 14:30:45 (默认格式)
fmt.Println(now.FormatDate())       // 2023-01-15
fmt.Println(now.FormatTime())       // 14:30:45
fmt.Println(now.FormatDateTime())   // 2023-01-15 14:30:45

// 国际标准格式
fmt.Println(now.FormatISO8601())    // 2023-01-15T14:30:45Z
fmt.Println(now.FormatRFC3339())    // 2023-01-15T14:30:45+08:00
fmt.Println(now.FormatRFC822())     // 15 Jan 23 14:30 CST

// 中文格式
fmt.Println(now.FormatChinese())    // 2023年01月15日 14时30分45秒
fmt.Println(now.FormatChineseDate()) // 2023年01月15日
fmt.Println(now.FormatChineseTime()) // 14时30分45秒

自定义格式

now := util.Now()

// 自定义格式字符串
fmt.Println(now.FormatCustom("2006/01/02 15:04:05"))  // 2023/01/15 14:30:45
fmt.Println(now.FormatCustom("Jan 2, 2006"))          // Jan 15, 2023
fmt.Println(now.FormatCustom("Monday, 2 January 2006")) // Sunday, 15 January 2023

// 链式格式化
formatted := now.
    ToUTC().                                          // 转换为UTC
    FormatCustom("2006-01-02T15:04:05Z")             // 格式化

// 带时区的格式化
beijing := now.InTimezone("Asia/Shanghai")
fmt.Println(beijing.FormatWithTimezone("Asia/Shanghai", "2006-01-02 15:04:05 MST"))

相对时间格式

now := util.Now()
past := now.AddDays(-3)
future := now.AddHours(2)

// 相对时间描述
fmt.Println(past.FormatRelative())    // "3 days ago"
fmt.Println(future.FormatRelative())  // "in 2 hours"

// 人性化时间差
fmt.Println(past.Humanize())          // "3天前"
fmt.Println(future.Humanize())        // "2小时后"

// 智能格式化
fmt.Println(past.FormatSmart())       // 根据时间差自动选择格式

⏱️ 时间运算

加减运算

now := util.Now()

// 时间单位加减
later := now.
    AddYears(1).        // 加1年
    AddMonths(2).       // 加2个月
    AddDays(15).        // 加15天
    AddHours(3).        // 加3小时
    AddMinutes(30).     // 加30分钟
    AddSeconds(45)      // 加45秒

// 减法运算
earlier := now.
    SubYears(1).        // 减1年
    SubMonths(2).       // 减2个月
    SubDays(15).        // 减15天
    SubHours(3).        // 减3小时
    SubMinutes(30).     // 减30分钟
    SubSeconds(45)      // 减45秒

// 时间段加减
duration := time.Hour * 2 + time.Minute * 30
withDuration := now.Add(duration)
withoutDuration := now.Sub(duration)

// 链式运算
result := now.
    AddDays(7).         // 加一周
    SetHour(9).         // 设置为9点
    SetMinute(0).       // 设置为0分
    SetSecond(0)        // 设置为0秒

设置时间组件

now := util.Now()

// 设置具体时间组件
modified := now.
    SetYear(2024).      // 设置年份
    SetMonth(12).       // 设置月份
    SetDay(25).         // 设置日期
    SetHour(18).        // 设置小时
    SetMinute(30).      // 设置分钟
    SetSecond(0).       // 设置秒数
    SetMillisecond(0)   // 设置毫秒

// 批量设置
dateTime := now.SetDate(2024, 12, 25)      // 设置日期
timeOnly := now.SetTime(18, 30, 0)         // 设置时间
complete := now.SetDateTime(2024, 12, 25, 18, 30, 0) // 设置完整时间

🌍 时区处理

时区转换

now := util.Now()

// 转换到不同时区
utc := now.ToUTC()                         // 转换为UTC
local := now.ToLocal()                     // 转换为本地时区
beijing := now.InTimezone("Asia/Shanghai") // 转换为北京时间
tokyo := now.InTimezone("Asia/Tokyo")      // 转换为东京时间
newYork := now.InTimezone("America/New_York") // 转换为纽约时间

// 时区偏移
offset8 := now.InOffset(8)                 // UTC+8
offsetMinus5 := now.InOffset(-5)           // UTC-5

// 获取时区信息
fmt.Println(now.TimezoneName())            // "CST"
fmt.Println(now.TimezoneOffset())          // 28800 (秒)
fmt.Println(now.TimezoneAbbr())            // "CST"

时区信息

now := util.Now()

// 检查时区
fmt.Println(now.IsUTC())                   // false
fmt.Println(now.IsLocal())                 // true
fmt.Println(now.IsDST())                   // 是否夏令时

// 时区列表
timezones := util.CommonTimezones()        // 常用时区列表
asian := util.AsianTimezones()             // 亚洲时区
american := util.AmericanTimezones()       // 美洲时区

// 时区验证
isValid := util.IsValidTimezone("Asia/Shanghai") // true

📊 时间比较

基础比较

t1 := util.ParseTime("2023-01-15 10:00:00", "2006-01-02 15:04:05")
t2 := util.ParseTime("2023-01-15 14:00:00", "2006-01-02 15:04:05")

// 比较操作
fmt.Println(t1.Equal(t2))       // false
fmt.Println(t1.Before(t2))      // true
fmt.Println(t1.After(t2))       // false

// 比较方法
fmt.Println(t1.Compare(t2))     // -1 (小于)
fmt.Println(t2.Compare(t1))     // 1 (大于)
fmt.Println(t1.Compare(t1))     // 0 (等于)

// 范围检查
start := util.ParseTime("2023-01-01", "2006-01-02")
end := util.ParseTime("2023-01-31", "2006-01-02")
current := util.ParseTime("2023-01-15", "2006-01-02")

fmt.Println(current.Between(start, end))    // true
fmt.Println(current.IsBetween(start, end))  // true (别名)

时间差计算

start := util.ParseTime("2023-01-01 10:00:00", "2006-01-02 15:04:05")
end := util.ParseTime("2023-01-15 14:30:45", "2006-01-02 15:04:05")

// 计算差值
duration := end.DiffTime(start)             // time.Duration
fmt.Println(duration)                       // 350h30m45s

// 具体单位的差值
fmt.Println(end.DiffDays(start))            // 14
fmt.Println(end.DiffHours(start))           // 350.5125
fmt.Println(end.DiffMinutes(start))         // 21030.75
fmt.Println(end.DiffSeconds(start))         // 1261845

// 绝对差值
fmt.Println(start.AbsDiff(end))             // 总是正数
fmt.Println(start.AbsDiffDays(end))         // 14

// 人性化差值描述
fmt.Println(end.DiffForHumans(start))       // "14天后"

📅 日期操作

日期边界

now := util.Now()

// 时间边界
startOfDay := now.StartOfDay()              // 当天开始 00:00:00
endOfDay := now.EndOfDay()                  // 当天结束 23:59:59
startOfWeek := now.StartOfWeek()            // 本周开始 (周一)
endOfWeek := now.EndOfWeek()                // 本周结束 (周日)
startOfMonth := now.StartOfMonth()          // 本月开始
endOfMonth := now.EndOfMonth()              // 本月结束
startOfYear := now.StartOfYear()            // 本年开始
endOfYear := now.EndOfYear()                // 本年结束

// 下一个边界
nextDay := now.NextDay()                    // 明天同一时间
nextWeek := now.NextWeek()                  // 下周同一时间
nextMonth := now.NextMonth()                // 下月同一天
nextYear := now.NextYear()                  // 明年同一天

// 上一个边界
prevDay := now.PrevDay()                    // 昨天同一时间
prevWeek := now.PrevWeek()                  // 上周同一时间
prevMonth := now.PrevMonth()                // 上月同一天
prevYear := now.PrevYear()                  // 去年同一天

日期判断

now := util.Now()
target := util.ParseTime("2023-01-15", "2006-01-02")

// 时间单位判断
fmt.Println(now.IsToday())                  // true/false
fmt.Println(target.IsYesterday())           // true/false
fmt.Println(target.IsTomorrow())            // true/false
fmt.Println(now.IsThisWeek())               // true
fmt.Println(now.IsThisMonth())              // true
fmt.Println(now.IsThisYear())               // true

// 相对判断
fmt.Println(target.IsPast())                // 是否是过去时间
fmt.Println(target.IsFuture())              // 是否是未来时间
fmt.Println(target.IsCurrentWeek())         // 是否在当前周
fmt.Println(target.IsCurrentMonth())        // 是否在当前月
fmt.Println(target.IsCurrentYear())         // 是否在当前年

// 特殊日期判断
fmt.Println(now.IsLeapYear())               // 是否闰年
fmt.Println(now.IsWeekend())                // 是否周末
fmt.Println(now.IsWeekday())                // 是否工作日

⏰ 高级功能

时间范围

// 创建时间范围
start := util.ParseTime("2023-01-01", "2006-01-02")
end := util.ParseTime("2023-01-31", "2006-01-02")
timeRange := util.NewTimeRange(start, end)

// 范围操作
fmt.Println(timeRange.Duration())           // 时间跨度
fmt.Println(timeRange.Contains(util.Now())) // 是否包含指定时间
fmt.Println(timeRange.IsValid())            // 范围是否有效

// 范围迭代
timeRange.EachDay(func(day *util.XTime) bool {
    fmt.Println(day.FormatDate())
    return true // 继续迭代
})

// 按小时迭代
timeRange.EachHour(func(hour *util.XTime) bool {
    fmt.Println(hour.FormatDateTime())
    return true
})

时间解析

// 智能解析
auto1 := util.ParseAuto("2023-01-15")          // 自动识别格式
auto2 := util.ParseAuto("2023/01/15 14:30")
auto3 := util.ParseAuto("Jan 15, 2023")

// 多格式尝试解析
formats := []string{
    "2006-01-02",
    "2006/01/02",
    "01/02/2006",
    "Jan 2, 2006",
}
parsed := util.ParseWithFormats("01/15/2023", formats...)

// 松散解析
loose := util.ParseLoose("next monday")        // 解析相对时间
flexible := util.ParseFlexible("in 2 hours")  // 解析时间短语

// 批量解析
timeStrings := []string{
    "2023-01-01", "2023-01-02", "2023-01-03",
}
times := util.ParseBatch(timeStrings, "2006-01-02")

时间缓存和性能

// 时间缓存
cache := util.NewTimeCache(time.Minute * 5)    // 5分钟缓存
now := cache.Now()                              // 缓存的当前时间

// 高性能时间戳
timestamp := util.FastTimestamp()               // 快速获取时间戳
milliTs := util.FastTimestampMilli()            // 快速获取毫秒时间戳

// 时间池
pool := util.NewTimePool()
t := pool.Get()                                 // 从池中获取
// 使用完后
pool.Put(t)                                     // 归还到池中

// 批量操作
times := util.NewTimeBatch()
times.Add(util.Now())
times.Add(util.Now().AddDays(1))
results := times.FormatAll("2006-01-02")        // 批量格式化

🔧 实际应用场景

日志和监控

// 日志时间戳
func LogWithTimestamp(level, message string) {
    timestamp := util.Now().FormatCustom("2006-01-02 15:04:05.000")
    fmt.Printf("[%s] %s: %s\n", timestamp, level, message)
}

// 性能监控
type PerformanceMonitor struct {
    startTime *util.XTime
}

func (pm *PerformanceMonitor) Start() {
    pm.startTime = util.Now()
}

func (pm *PerformanceMonitor) End() time.Duration {
    return util.Now().DiffTime(pm.startTime)
}

// 请求耗时统计
func TrackRequestTime(handler http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        start := util.Now()
        handler(w, r)
        duration := util.Now().DiffTime(start)
        
        log.Printf("Request %s took %v", r.URL.Path, duration)
    }
}

任务调度

// 定时任务
type ScheduledTask struct {
    name     string
    nextRun  *util.XTime
    interval time.Duration
}

func (st *ScheduledTask) ShouldRun() bool {
    return util.Now().After(st.nextRun)
}

func (st *ScheduledTask) UpdateNextRun() {
    st.nextRun = util.Now().Add(st.interval)
}

// 日程管理
type Calendar struct {
    events map[string]*util.XTime
}

func (c *Calendar) AddEvent(name string, when *util.XTime) {
    c.events[name] = when
}

func (c *Calendar) GetUpcomingEvents(within time.Duration) []string {
    var upcoming []string
    cutoff := util.Now().Add(within)
    
    for name, eventTime := range c.events {
        if eventTime.Between(util.Now(), cutoff) {
            upcoming = append(upcoming, name)
        }
    }
    return upcoming
}

// 工作日计算
func CalculateWorkdays(start, end *util.XTime) int {
    workdays := 0
    current := start.Clone()
    
    for current.Before(end) || current.Equal(end) {
        if current.IsWeekday() {
            workdays++
        }
        current = current.AddDays(1)
    }
    
    return workdays
}

数据分析

// 时间序列数据处理
type TimeSeriesData struct {
    Timestamp *util.XTime
    Value     float64
}

func AnalyzeTimeSeries(data []TimeSeriesData) map[string]interface{} {
    if len(data) == 0 {
        return nil
    }
    
    // 按日分组
    dailyData := make(map[string][]float64)
    for _, point := range data {
        day := point.Timestamp.FormatDate()
        dailyData[day] = append(dailyData[day], point.Value)
    }
    
    // 统计分析
    analysis := make(map[string]interface{})
    analysis["total_days"] = len(dailyData)
    analysis["date_range"] = map[string]string{
        "start": data[0].Timestamp.FormatDate(),
        "end":   data[len(data)-1].Timestamp.FormatDate(),
    }
    
    return analysis
}

// 活跃时间分析
func AnalyzeUserActivity(loginTimes []*util.XTime) map[int]int {
    hourlyActivity := make(map[int]int)
    
    for _, loginTime := range loginTimes {
        hour := loginTime.Hour()
        hourlyActivity[hour]++
    }
    
    return hourlyActivity
}

// 业务时间计算
func CalculateBusinessHours(start, end *util.XTime) time.Duration {
    if start.IsWeekend() || end.IsWeekend() {
        return 0 // 周末不计入业务时间
    }
    
    // 业务时间: 9:00-18:00
    businessStart := start.SetTime(9, 0, 0)
    businessEnd := start.SetTime(18, 0, 0)
    
    actualStart := start
    if start.Before(businessStart) {
        actualStart = businessStart
    }
    
    actualEnd := end
    if end.After(businessEnd) {
        actualEnd = businessEnd
    }
    
    if actualEnd.Before(actualStart) {
        return 0
    }
    
    return actualEnd.DiffTime(actualStart)
}

国际化时间

// 多语言时间格式
type LocalizedTime struct {
    time   *util.XTime
    locale string
}

func NewLocalizedTime(t *util.XTime, locale string) *LocalizedTime {
    return &LocalizedTime{time: t, locale: locale}
}

func (lt *LocalizedTime) Format() string {
    switch lt.locale {
    case "zh-CN":
        return lt.time.FormatChinese()
    case "en-US":
        return lt.time.FormatCustom("January 2, 2006 3:04 PM")
    case "ja-JP":
        return lt.time.FormatCustom("2006年1月2日 15時04分")
    default:
        return lt.time.Format()
    }
}

// 时区会议调度
func ScheduleGlobalMeeting(baseTime *util.XTime, timezones []string) map[string]string {
    schedule := make(map[string]string)
    
    for _, tz := range timezones {
        localTime := baseTime.InTimezone(tz)
        schedule[tz] = localTime.FormatCustom("Jan 2, 15:04 MST")
    }
    
    return schedule
}

// 营业时间检查
func IsBusinessOpen(timezone string) bool {
    localTime := util.Now().InTimezone(timezone)
    
    // 营业时间: 周一至周五 9:00-18:00
    if localTime.IsWeekend() {
        return false
    }
    
    hour := localTime.Hour()
    return hour >= 9 && hour < 18
}

📊 性能基准

基准测试结果

操作类型                    性能指标
Now()                      纳秒级
Format操作                 微秒级
时区转换                   微秒级
时间解析                   微秒级
时间运算                   纳秒级
比较操作                   纳秒级

性能优化技巧

// ✅ 使用缓存减少系统调用
cache := util.NewTimeCache(time.Second)
now := cache.Now()  // 缓存1秒内的当前时间

// ✅ 预编译时间格式
var customFormat = "2006-01-02 15:04:05"
formatted := now.FormatCustom(customFormat)

// ✅ 批量操作
times := []string{"2023-01-01", "2023-01-02", "2023-01-03"}
parsed := util.ParseBatch(times, "2006-01-02")

// ✅ 对象池复用
pool := util.NewTimePool()
t := pool.Get()
defer pool.Put(t)

// ❌ 避免频繁的时区转换
for i := 0; i < 1000; i++ {
    _ = now.InTimezone("Asia/Shanghai")  // 每次都转换
}

// ✅ 一次转换,多次使用
beijingTime := now.InTimezone("Asia/Shanghai")
for i := 0; i < 1000; i++ {
    _ = beijingTime.Format()  // 使用已转换的时间
}

🎯 最佳实践

1. 时区处理

// ✅ 明确指定时区
utcTime := util.NowUTC()
localTime := utcTime.InTimezone("Asia/Shanghai")

// ✅ 存储时使用UTC,显示时转换为本地时区
func SaveEvent(eventTime *util.XTime) {
    utcTime := eventTime.ToUTC()
    // 存储 utcTime 到数据库
}

func DisplayEvent(utcTime *util.XTime, userTimezone string) string {
    localTime := utcTime.InTimezone(userTimezone)
    return localTime.FormatDateTime()
}

// ❌ 避免混用不同时区的时间

2. 性能优化

// ✅ 使用适当的精度
timestamp := util.FastTimestamp()        // 秒级精度
milliTs := util.FastTimestampMilli()     // 毫秒级精度

// ✅ 缓存频繁使用的时间
startOfToday := util.Now().StartOfDay()

// ✅ 批量处理
var times []*util.XTime
// ... 收集时间
formatted := util.FormatBatch(times, "2006-01-02")

3. 错误处理

// ✅ 安全解析时间
parsed, err := util.ParseSafe("2023-13-01", "2006-01-02")
if err != nil {
    log.Printf("时间解析失败: %v", err)
    return
}

// ✅ 使用默认值
parsed := util.ParseOrDefault("invalid", "2006-01-02", util.Now())

// ✅ 验证时间范围
if !timeValue.Between(minTime, maxTime) {
    return errors.New("时间超出有效范围")
}

🔗 相关资源

💬 获取帮助

如果您在使用 XTime 时遇到问题:


🎉 现在您已经掌握了 XTime 的强大功能,开始在项目中使用这些优雅的时间操作吧!