diff --git a/docs/factory.md b/docs/factory.md index 9865a97..74acc83 100644 --- a/docs/factory.md +++ b/docs/factory.md @@ -27,6 +27,8 @@ | **短信** | `SendSMS()` | `fac.SendSMS(phones, params)` | | **存储** | `UploadFile()`, `GetFileURL()` | `fac.UploadFile(ctx, key, file)` | | **日期时间** | `Now()`, `ParseDateTime()`, `FormatDateTime()` 等 | `fac.Now("Asia/Shanghai")` | +| **时间工具** | `GetTimestamp()`, `IsToday()`, `GetBeginOfWeek()` 等 | `fac.GetTimestamp()` | +| **加密工具** | `HashPassword()`, `MD5()`, `SHA256()`, `GenerateSMSCode()` 等 | `fac.HashPassword("password")` | | **金额计算** | `YuanToCents()`, `CentsToYuan()`, `FormatYuan()` | `fac.YuanToCents(100.5)` | | **版本信息** | `GetVersion()` | `fac.GetVersion()` | | **HTTP响应** | `Success()`, `Error()`, `SuccessPage()` | `fac.Success(w, data)` | @@ -203,7 +205,42 @@ unix := fac.ToUnix(now) t2 := fac.FromUnix(unix, "Asia/Shanghai") ``` -### 9. 金额计算(黑盒模式) +### 9. 时间操作(黑盒模式) + +```go +// 时间戳 +timestamp := fac.GetTimestamp() // 当前时间戳(秒) +millisTimestamp := fac.GetMillisTimestamp() // 当前时间戳(毫秒) +utcTimestamp := fac.GetUTCTimestamp() // UTC时间戳 + +// 自定义格式格式化 +str := fac.FormatTimeWithLayout(now, "2006年01月02日 15:04:05") + +// 自定义格式解析 +t, _ := fac.ParseTime("2024-01-01 12:00:00", "2006-01-02 15:04:05") + +// 时间计算(补充) +nextHour := fac.AddHours(now, 1) +nextMinute := fac.AddMinutes(now, 30) + +// 周相关 +beginOfWeek := fac.GetBeginOfWeek(now) +endOfWeek := fac.GetEndOfWeek(now) + +// 时间判断 +if fac.IsToday(t) { + fmt.Println("是今天") +} +if fac.IsYesterday(t) { + fmt.Println("是昨天") +} + +// 生成详细时间信息 +timeInfo := fac.GenerateTimeInfoWithTimezone(now, "Asia/Shanghai") +fmt.Printf("UTC: %s, Local: %s, Unix: %d\n", timeInfo.UTC, timeInfo.Local, timeInfo.Unix) +``` + +### 10. 金额计算(黑盒模式) ```go // 元转分 @@ -216,14 +253,14 @@ yuan := fac.CentsToYuan(10050) // 100.5 str := fac.FormatYuan(10050) // "100.50" ``` -### 10. 版本信息(黑盒模式) +### 12. 版本信息(黑盒模式) ```go version := fac.GetVersion() fmt.Println("当前版本:", version) ``` -### 11. HTTP响应(黑盒模式) +### 13. HTTP响应(黑盒模式) ```go import "net/http" @@ -240,7 +277,7 @@ fac.Error(w, 1001, "用户不存在") fac.SystemError(w, "系统错误") ``` -### 12. HTTP请求解析(黑盒模式) +### 14. HTTP请求解析(黑盒模式) ```go import "net/http" @@ -257,7 +294,7 @@ keyword := fac.GetQuery(r, "keyword", "") timezone := fac.GetTimezone(r) ``` -### 13. Redis操作(获取客户端对象) +### 15. Redis操作(获取客户端对象) ```go import ( @@ -735,6 +772,266 @@ fac.Success(w, user, "获取成功") // 自定义消息 计算两个时间之间的秒数差。 +### 加密工具方法(黑盒模式) + +#### 密码加密 + +##### HashPassword(password string) (string, error) + +使用bcrypt加密密码。 + +**参数:** +- `password`: 原始密码 + +**返回:** 加密后的密码哈希值和错误信息 + +**示例:** +```go +hashedPassword, err := fac.HashPassword("myPassword") +``` + +##### CheckPassword(password, hash string) bool + +验证密码。 + +**参数:** +- `password`: 原始密码 +- `hash`: 加密后的密码哈希值 + +**返回:** 密码是否正确 + +**示例:** +```go +isValid := fac.CheckPassword("myPassword", hashedPassword) +``` + +#### 哈希计算 + +##### MD5(text string) string + +计算MD5哈希值。 + +**参数:** +- `text`: 要计算哈希的文本 + +**返回:** MD5哈希值(十六进制字符串) + +**示例:** +```go +hash := fac.MD5("text") +``` + +##### SHA256(text string) string + +计算SHA256哈希值。 + +**参数:** +- `text`: 要计算哈希的文本 + +**返回:** SHA256哈希值(十六进制字符串) + +**示例:** +```go +hash := fac.SHA256("text") +``` + +#### 随机字符串生成 + +##### GenerateRandomString(length int) string + +生成指定长度的随机字符串。 + +**参数:** +- `length`: 字符串长度 + +**返回:** 随机字符串(包含大小写字母和数字) + +**示例:** +```go +randomStr := fac.GenerateRandomString(16) +``` + +##### GenerateRandomNumber(length int) string + +生成指定长度的随机数字字符串。 + +**参数:** +- `length`: 字符串长度 + +**返回:** 随机数字字符串 + +**示例:** +```go +randomNum := fac.GenerateRandomNumber(6) +``` + +#### 业务相关随机码生成 + +##### GenerateSMSCode() string + +生成短信验证码。 + +**返回:** 6位数字验证码 + +**示例:** +```go +code := fac.GenerateSMSCode() +``` + +##### GenerateOrderNo(prefix string) string + +生成订单号。 + +**参数:** +- `prefix`: 订单号前缀 + +**返回:** 订单号(格式:前缀+时间戳+6位随机数) + +**示例:** +```go +orderNo := fac.GenerateOrderNo("ORD") +``` + +##### GeneratePaymentNo() string + +生成支付单号。 + +**返回:** 支付单号(格式:PAY+时间戳+6位随机数) + +**示例:** +```go +paymentNo := fac.GeneratePaymentNo() +``` + +##### GenerateRefundNo() string + +生成退款单号。 + +**返回:** 退款单号(格式:RF+时间戳+6位随机数) + +**示例:** +```go +refundNo := fac.GenerateRefundNo() +``` + +##### GenerateTransferNo() string + +生成调拨单号。 + +**返回:** 调拨单号(格式:TF+时间戳+6位随机数) + +**示例:** +```go +transferNo := fac.GenerateTransferNo() +``` + +### 时间工具方法(黑盒模式) + +**说明**:Time 工具提供基础时间操作、时间戳、时间判断等功能,与 DateTime 工具的区别: +- **DateTime**:专注于时区相关、格式化、解析、UTC转换 +- **Time**:专注于基础时间操作、时间戳、时间判断、时间信息生成 + +#### 时间戳方法 + +##### GetTimestamp() int64 + +获取当前时间戳(秒)。 + +##### GetMillisTimestamp() int64 + +获取当前时间戳(毫秒)。 + +##### GetUTCTimestamp() int64 + +获取UTC时间戳(秒)。 + +##### GetUTCTimestampFromTime(t time.Time) int64 + +从指定时间获取UTC时间戳(秒)。 + +#### 格式化方法(自定义格式) + +##### FormatTimeWithLayout(t time.Time, layout string) string + +格式化时间(自定义格式)。 + +**参数:** +- `t`: 时间对象 +- `layout`: 时间格式,如 "2006-01-02 15:04:05",如果为空则使用默认格式 + +##### FormatTimeUTC(t time.Time) string + +格式化时间为UTC字符串(ISO 8601格式)。 + +##### GetCurrentTime() string + +获取当前时间字符串(使用默认格式 "2006-01-02 15:04:05")。 + +#### 解析方法(自定义格式) + +##### ParseTime(timeStr, layout string) (time.Time, error) + +解析时间字符串(自定义格式)。 + +**参数:** +- `timeStr`: 时间字符串 +- `layout`: 时间格式,如 "2006-01-02 15:04:05",如果为空则使用默认格式 + +#### 时间计算(补充 DateTime 的 Add 系列) + +##### AddHours(t time.Time, hours int) time.Time + +增加小时数。 + +##### AddMinutes(t time.Time, minutes int) time.Time + +增加分钟数。 + +#### 时间范围(周相关) + +##### GetBeginOfWeek(t time.Time) time.Time + +获取某周的开始时间(周一)。 + +##### GetEndOfWeek(t time.Time) time.Time + +获取某周的结束时间(周日)。 + +#### 时间判断 + +##### IsToday(t time.Time) bool + +判断是否为今天。 + +##### IsYesterday(t time.Time) bool + +判断是否为昨天。 + +##### IsTomorrow(t time.Time) bool + +判断是否为明天。 + +#### 时间信息生成 + +##### GenerateTimeInfoWithTimezone(t time.Time, timezone string) TimeInfo + +生成详细时间信息(指定时区)。 + +**参数:** +- `t`: 时间对象 +- `timezone`: 时区字符串,如 "Asia/Shanghai" + +**返回:** TimeInfo 结构体,包含: +- `UTC`: UTC时间(RFC3339格式) +- `Local`: 本地时间(RFC3339格式) +- `Unix`: Unix时间戳(秒) +- `Timezone`: 时区名称 +- `Offset`: 时区偏移量(小时) +- `RFC3339`: RFC3339格式时间 +- `DateTime`: 日期时间格式(2006-01-02 15:04:05) +- `Date`: 日期格式(2006-01-02) +- `Time`: 时间格式(15:04:05) + ### 金额工具方法(黑盒模式) #### GetMoneyCalculator() *tools.MoneyCalculator diff --git a/factory/factory.go b/factory/factory.go index 3a9adfc..e6338ef 100644 --- a/factory/factory.go +++ b/factory/factory.go @@ -68,6 +68,12 @@ type PageData = commonhttp.PageData // } type PaginationRequest = commonhttp.PaginationRequest +// ========== Time工具结构体(暴露给外部项目使用) ========== + +// TimeInfo 详细时间信息结构(暴露给外部项目使用) +// 外部项目可以直接使用 factory.TimeInfo 创建时间信息对象 +type TimeInfo = tools.TimeInfo + // Factory 工厂类 - 黑盒模式设计 // // 核心理念: @@ -1195,3 +1201,195 @@ func (f *Factory) DiffMinutes(t1, t2 time.Time) int64 { func (f *Factory) DiffSeconds(t1, t2 time.Time) int64 { return tools.DiffSeconds(t1, t2) } + +// ========== Time 时间工具(黑盒模式,推荐使用) ========== +// +// 这些方法提供基础时间操作、时间戳、时间判断等功能。 +// 与 DateTime 工具的区别: +// - DateTime: 专注于时区相关、格式化、解析、UTC转换 +// - Time: 专注于基础时间操作、时间戳、时间判断、时间信息生成 + +// ========== 时间戳方法 ========== + +// GetTimestamp 获取当前时间戳(秒)(黑盒模式,推荐使用) +func (f *Factory) GetTimestamp() int64 { + return tools.GetTimestamp() +} + +// GetMillisTimestamp 获取当前时间戳(毫秒)(黑盒模式,推荐使用) +func (f *Factory) GetMillisTimestamp() int64 { + return tools.GetMillisTimestamp() +} + +// GetUTCTimestamp 获取UTC时间戳(秒)(黑盒模式,推荐使用) +func (f *Factory) GetUTCTimestamp() int64 { + return tools.GetUTCTimestamp() +} + +// GetUTCTimestampFromTime 从指定时间获取UTC时间戳(秒)(黑盒模式,推荐使用) +func (f *Factory) GetUTCTimestampFromTime(t time.Time) int64 { + return tools.GetUTCTimestampFromTime(t) +} + +// ========== 格式化方法(自定义格式) ========== + +// FormatTimeWithLayout 格式化时间(自定义格式)(黑盒模式,推荐使用) +// layout: 时间格式,如 "2006-01-02 15:04:05",如果为空则使用默认格式 +func (f *Factory) FormatTimeWithLayout(t time.Time, layout string) string { + return tools.FormatTimeWithLayout(t, layout) +} + +// FormatTimeUTC 格式化时间为UTC字符串(ISO 8601格式)(黑盒模式,推荐使用) +func (f *Factory) FormatTimeUTC(t time.Time) string { + return tools.FormatTimeUTC(t) +} + +// GetCurrentTime 获取当前时间字符串(黑盒模式,推荐使用) +// 使用默认格式 "2006-01-02 15:04:05" +func (f *Factory) GetCurrentTime() string { + return tools.GetCurrentTime() +} + +// ========== 解析方法(自定义格式) ========== + +// ParseTime 解析时间字符串(自定义格式)(黑盒模式,推荐使用) +// timeStr: 时间字符串 +// layout: 时间格式,如 "2006-01-02 15:04:05",如果为空则使用默认格式 +func (f *Factory) ParseTime(timeStr, layout string) (time.Time, error) { + return tools.ParseTime(timeStr, layout) +} + +// ========== 时间计算(补充 DateTime 的 Add 系列) ========== + +// AddHours 增加小时数(黑盒模式,推荐使用) +func (f *Factory) AddHours(t time.Time, hours int) time.Time { + return tools.AddHours(t, hours) +} + +// AddMinutes 增加分钟数(黑盒模式,推荐使用) +func (f *Factory) AddMinutes(t time.Time, minutes int) time.Time { + return tools.AddMinutes(t, minutes) +} + +// ========== 时间范围(周相关) ========== + +// GetBeginOfWeek 获取某周的开始时间(周一)(黑盒模式,推荐使用) +func (f *Factory) GetBeginOfWeek(t time.Time) time.Time { + return tools.GetBeginOfWeek(t) +} + +// GetEndOfWeek 获取某周的结束时间(周日)(黑盒模式,推荐使用) +func (f *Factory) GetEndOfWeek(t time.Time) time.Time { + return tools.GetEndOfWeek(t) +} + +// ========== 时间判断 ========== + +// IsToday 判断是否为今天(黑盒模式,推荐使用) +func (f *Factory) IsToday(t time.Time) bool { + return tools.IsToday(t) +} + +// IsYesterday 判断是否为昨天(黑盒模式,推荐使用) +func (f *Factory) IsYesterday(t time.Time) bool { + return tools.IsYesterday(t) +} + +// IsTomorrow 判断是否为明天(黑盒模式,推荐使用) +func (f *Factory) IsTomorrow(t time.Time) bool { + return tools.IsTomorrow(t) +} + +// ========== 时间信息生成 ========== + +// GenerateTimeInfoWithTimezone 生成详细时间信息(指定时区)(黑盒模式,推荐使用) +// 返回包含UTC时间、本地时间、时间戳、时区信息等的完整时间信息结构 +func (f *Factory) GenerateTimeInfoWithTimezone(t time.Time, timezone string) TimeInfo { + return tools.GenerateTimeInfoWithTimezone(t, timezone) +} + +// ========== Crypto 加密工具(黑盒模式,推荐使用) ========== +// +// 这些方法提供密码加密、哈希计算、随机字符串生成等功能。 + +// ========== 密码加密 ========== + +// HashPassword 使用bcrypt加密密码(黑盒模式,推荐使用) +// password: 原始密码 +// 返回: 加密后的密码哈希值 +func (f *Factory) HashPassword(password string) (string, error) { + return tools.HashPassword(password) +} + +// CheckPassword 验证密码(黑盒模式,推荐使用) +// password: 原始密码 +// hash: 加密后的密码哈希值 +// 返回: 密码是否正确 +func (f *Factory) CheckPassword(password, hash string) bool { + return tools.CheckPassword(password, hash) +} + +// ========== 哈希计算 ========== + +// MD5 计算MD5哈希值(黑盒模式,推荐使用) +// text: 要计算哈希的文本 +// 返回: MD5哈希值(十六进制字符串) +func (f *Factory) MD5(text string) string { + return tools.MD5(text) +} + +// SHA256 计算SHA256哈希值(黑盒模式,推荐使用) +// text: 要计算哈希的文本 +// 返回: SHA256哈希值(十六进制字符串) +func (f *Factory) SHA256(text string) string { + return tools.SHA256(text) +} + +// ========== 随机字符串生成 ========== + +// GenerateRandomString 生成指定长度的随机字符串(黑盒模式,推荐使用) +// length: 字符串长度 +// 返回: 随机字符串(包含大小写字母和数字) +func (f *Factory) GenerateRandomString(length int) string { + return tools.GenerateRandomString(length) +} + +// GenerateRandomNumber 生成指定长度的随机数字字符串(黑盒模式,推荐使用) +// length: 字符串长度 +// 返回: 随机数字字符串 +func (f *Factory) GenerateRandomNumber(length int) string { + return tools.GenerateRandomNumber(length) +} + +// ========== 业务相关随机码生成 ========== + +// GenerateSMSCode 生成短信验证码(黑盒模式,推荐使用) +// 返回: 6位数字验证码 +func (f *Factory) GenerateSMSCode() string { + return tools.GenerateSMSCode() +} + +// GenerateOrderNo 生成订单号(黑盒模式,推荐使用) +// prefix: 订单号前缀 +// 返回: 订单号(格式:前缀+时间戳+6位随机数) +func (f *Factory) GenerateOrderNo(prefix string) string { + return tools.GenerateOrderNo(prefix) +} + +// GeneratePaymentNo 生成支付单号(黑盒模式,推荐使用) +// 返回: 支付单号(格式:PAY+时间戳+6位随机数) +func (f *Factory) GeneratePaymentNo() string { + return tools.GeneratePaymentNo() +} + +// GenerateRefundNo 生成退款单号(黑盒模式,推荐使用) +// 返回: 退款单号(格式:RF+时间戳+6位随机数) +func (f *Factory) GenerateRefundNo() string { + return tools.GenerateRefundNo() +} + +// GenerateTransferNo 生成调拨单号(黑盒模式,推荐使用) +// 返回: 调拨单号(格式:TF+时间戳+6位随机数) +func (f *Factory) GenerateTransferNo() string { + return tools.GenerateTransferNo() +} diff --git a/tools/crypto.go b/tools/crypto.go new file mode 100644 index 0000000..962a7c4 --- /dev/null +++ b/tools/crypto.go @@ -0,0 +1,85 @@ +package tools + +import ( + "crypto/md5" + "crypto/rand" + "crypto/sha256" + "encoding/hex" + "fmt" + "math/big" + + "golang.org/x/crypto/bcrypt" +) + +// HashPassword 使用bcrypt加密密码 +func HashPassword(password string) (string, error) { + bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + return string(bytes), err +} + +// CheckPassword 验证密码 +func CheckPassword(password, hash string) bool { + err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) + return err == nil +} + +// MD5 计算MD5哈希值 +func MD5(text string) string { + hash := md5.Sum([]byte(text)) + return hex.EncodeToString(hash[:]) +} + +// SHA256 计算SHA256哈希值 +func SHA256(text string) string { + hash := sha256.Sum256([]byte(text)) + return hex.EncodeToString(hash[:]) +} + +// GenerateRandomString 生成指定长度的随机字符串 +func GenerateRandomString(length int) string { + const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + b := make([]byte, length) + for i := range b { + num, _ := rand.Int(rand.Reader, big.NewInt(int64(len(charset)))) + b[i] = charset[num.Int64()] + } + return string(b) +} + +// GenerateRandomNumber 生成指定长度的随机数字字符串 +func GenerateRandomNumber(length int) string { + const charset = "0123456789" + b := make([]byte, length) + for i := range b { + num, _ := rand.Int(rand.Reader, big.NewInt(int64(len(charset)))) + b[i] = charset[num.Int64()] + } + return string(b) +} + +// GenerateSMSCode 生成短信验证码 +func GenerateSMSCode() string { + return GenerateRandomNumber(6) +} + +// GenerateOrderNo 生成订单号 +func GenerateOrderNo(prefix string) string { + timestamp := GetTimestamp() + random := GenerateRandomNumber(6) + return fmt.Sprintf("%s%d%s", prefix, timestamp, random) +} + +// GeneratePaymentNo 生成支付单号 +func GeneratePaymentNo() string { + return GenerateOrderNo("PAY") +} + +// GenerateRefundNo 生成退款单号 +func GenerateRefundNo() string { + return GenerateOrderNo("RF") +} + +// GenerateTransferNo 生成调拨单号 +func GenerateTransferNo() string { + return GenerateOrderNo("TF") +} diff --git a/tools/time.go b/tools/time.go new file mode 100644 index 0000000..00df0a0 --- /dev/null +++ b/tools/time.go @@ -0,0 +1,186 @@ +package tools + +import ( + "time" +) + +// TimeInfo 详细时间信息结构 +type TimeInfo struct { + UTC string `json:"utc"` // UTC时间 + Local string `json:"local"` // 用户时区时间 + Unix int64 `json:"unix"` // Unix时间戳 + Timezone string `json:"timezone"` // 时区名称 + Offset int `json:"offset"` // 时区偏移量(小时) + RFC3339 string `json:"rfc3339"` // RFC3339格式 + DateTime string `json:"datetime"` // 日期时间格式 + Date string `json:"date"` // 日期格式 + Time string `json:"time"` // 时间格式 +} + +// GetTimestamp 获取当前时间戳(秒) +func GetTimestamp() int64 { + return time.Now().Unix() +} + +// GetMillisTimestamp 获取当前时间戳(毫秒) +func GetMillisTimestamp() int64 { + return time.Now().UnixMilli() +} + +// FormatTimeWithLayout 格式化时间(自定义格式) +func FormatTimeWithLayout(t time.Time, layout string) string { + if layout == "" { + layout = "2006-01-02 15:04:05" + } + return t.Format(layout) +} + +// ParseTime 解析时间字符串 +func ParseTime(timeStr, layout string) (time.Time, error) { + if layout == "" { + layout = "2006-01-02 15:04:05" + } + return time.Parse(layout, timeStr) +} + +// GetCurrentTime 获取当前时间字符串 +func GetCurrentTime() string { + return FormatTimeWithLayout(time.Now(), "") +} + +// 注意:GetBeginOfDay、GetEndOfDay 已在 datetime.go 中实现为 StartOfDay、EndOfDay +// datetime.go 中的方法支持时区参数,功能更强大,建议使用 datetime.go 中的方法 + +// GetBeginOfWeek 获取某周的开始时间(周一) +func GetBeginOfWeek(t time.Time) time.Time { + weekday := t.Weekday() + if weekday == time.Sunday { + weekday = 7 + } + // 使用 datetime.go 中的 StartOfDay 方法(需要时区,这里使用时间对象本身的时区) + beginDay := t.AddDate(0, 0, int(1-weekday)) + return time.Date(beginDay.Year(), beginDay.Month(), beginDay.Day(), 0, 0, 0, 0, beginDay.Location()) +} + +// GetEndOfWeek 获取某周的结束时间(周日) +func GetEndOfWeek(t time.Time) time.Time { + beginOfWeek := GetBeginOfWeek(t) + endDay := beginOfWeek.AddDate(0, 0, 6) + return time.Date(endDay.Year(), endDay.Month(), endDay.Day(), 23, 59, 59, 999999999, endDay.Location()) +} + +// 注意:GetBeginOfMonth、GetEndOfMonth、GetBeginOfYear、GetEndOfYear 已在 datetime.go 中实现 +// datetime.go 中的方法(StartOfMonth、EndOfMonth、StartOfYear、EndOfYear)支持时区参数,功能更强大 +// 建议使用 datetime.go 中的方法 + +// AddHours 增加小时数 +func AddHours(t time.Time, hours int) time.Time { + return t.Add(time.Duration(hours) * time.Hour) +} + +// AddMinutes 增加分钟数 +func AddMinutes(t time.Time, minutes int) time.Time { + return t.Add(time.Duration(minutes) * time.Minute) +} + +// 注意:DiffDays、DiffHours、DiffMinutes、DiffSeconds 方法已在 datetime.go 中实现 +// 请使用 datetime.go 中的方法,它们支持更精确的计算和统一的返回类型 + +// IsToday 判断是否为今天 +func IsToday(t time.Time) bool { + now := time.Now() + tBegin := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()) + nowBegin := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) + return tBegin.Equal(nowBegin) +} + +// GenerateTimeInfoWithTimezone 生成详细时间信息(指定时区) +func GenerateTimeInfoWithTimezone(t time.Time, timezone string) TimeInfo { + // 加载时区 + loc, err := time.LoadLocation(timezone) + if err != nil { + loc = time.UTC + timezone = "UTC" + } + + // 转换为指定时区时间 + localTime := t.In(loc) + + // 计算时区偏移量 + _, offset := localTime.Zone() + offsetHours := offset / 3600 + + // 预先计算格式化结果,避免重复调用 + utcRFC3339 := t.UTC().Format(time.RFC3339) + localRFC3339 := localTime.Format(time.RFC3339) + localDateTime := localTime.Format("2006-01-02 15:04:05") + localDate := localTime.Format("2006-01-02") + localTimeOnly := localTime.Format("15:04:05") + + return TimeInfo{ + UTC: utcRFC3339, + Local: localRFC3339, + Unix: t.Unix(), + Timezone: timezone, + Offset: offsetHours, + RFC3339: localRFC3339, + DateTime: localDateTime, + Date: localDate, + Time: localTimeOnly, + } +} + +// GetUTCTimestamp 获取UTC时间戳 +func GetUTCTimestamp() int64 { + return time.Now().UTC().Unix() +} + +// GetUTCTimestampFromTime 从指定时间获取UTC时间戳 +func GetUTCTimestampFromTime(t time.Time) int64 { + return t.UTC().Unix() +} + +// FormatTimeUTC 格式化时间为UTC字符串(ISO 8601格式) +func FormatTimeUTC(t time.Time) string { + return t.UTC().Format(time.RFC3339) +} + +// IsYesterday 判断是否为昨天 +func IsYesterday(t time.Time) bool { + yesterday := time.Now().AddDate(0, 0, -1) + tBegin := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()) + yesterdayBegin := time.Date(yesterday.Year(), yesterday.Month(), yesterday.Day(), 0, 0, 0, 0, yesterday.Location()) + return tBegin.Equal(yesterdayBegin) +} + +// IsTomorrow 判断是否为明天 +func IsTomorrow(t time.Time) bool { + tomorrow := time.Now().AddDate(0, 0, 1) + tBegin := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()) + tomorrowBegin := time.Date(tomorrow.Year(), tomorrow.Month(), tomorrow.Day(), 0, 0, 0, 0, tomorrow.Location()) + return tBegin.Equal(tomorrowBegin) +} + +// GenerateTimeInfoFromContext 从gin.Context中获取用户时区并生成时间信息 +func GenerateTimeInfoFromContext(t time.Time, c interface{}) TimeInfo { + // 尝试从context中获取时区 + timezone := "" + + // 如果传入的是gin.Context,尝试获取时区 + if ginCtx, ok := c.(interface { + Get(key string) (value interface{}, exists bool) + }); ok { + if tz, exists := ginCtx.Get("user_timezone"); exists { + if tzStr, ok := tz.(string); ok && tzStr != "" { + timezone = tzStr + } + } + } + + // 如果没有获取到时区,使用默认时区(东8区) + if timezone == "" { + timezone = "Asia/Shanghai" + } + + return GenerateTimeInfoWithTimezone(t, timezone) +}