This commit is contained in:
Joe
2026-01-16 15:49:34 +08:00
commit 550d3e1f42
380 changed files with 62024 additions and 0 deletions
+213
View File
@@ -0,0 +1,213 @@
package helpers
import (
"goravel/app/utils"
"time"
"github.com/goravel/framework/contracts/http"
"github.com/goravel/framework/facades"
"github.com/goravel/framework/support/carbon"
"github.com/goravel/framework/support/str"
)
// GetCurrentTimezone 获取当前请求的时区
// 优先从请求头 X-Timezone 或 Timezone 获取
// 如果请求头没有或时区无效,使用配置的默认时区
func GetCurrentTimezone(ctx http.Context) string {
// 优先从 X-Timezone 请求头获取
timezone := ctx.Request().Header("X-Timezone", "")
if timezone == "" {
// 尝试从 Timezone 请求头获取
timezone = ctx.Request().Header("Timezone", "")
}
if timezone == "" {
// 尝试从查询参数获取
timezone = ctx.Request().Input("timezone")
}
// 如果从请求中获取到了时区,规范化并返回
if timezone != "" {
return NormalizeTimezone(timezone)
}
// 如果都没有,使用配置的默认时区
defaultTimezone := facades.Config().GetString("app.timezone", carbon.UTC)
return NormalizeTimezone(defaultTimezone)
}
// isValidTimezone 验证时区是否有效
func isValidTimezone(timezone string) bool {
if timezone == "" {
return false
}
// 尝试加载时区
_, err := time.LoadLocation(timezone)
return err == nil
}
// NormalizeTimezone 规范化时区名称(处理常见别名)
func NormalizeTimezone(timezone string) string {
timezone = str.Of(timezone).Trim().String()
if str.Of(timezone).IsEmpty() {
return carbon.UTC
}
// 转换为标准时区名称
timezoneMap := map[string]string{
"UTC": "UTC",
"GMT": "UTC",
"PST": "America/Los_Angeles",
"PDT": "America/Los_Angeles",
"EST": "America/New_York",
"EDT": "America/New_York",
"CST": "America/Chicago",
"CDT": "America/Chicago",
"MST": "America/Denver",
"MDT": "America/Denver",
"Beijing": "Asia/Shanghai",
"Shanghai": "Asia/Shanghai",
"Hong Kong": "Asia/Hong_Kong",
"Tokyo": "Asia/Tokyo",
"Seoul": "Asia/Seoul",
"Singapore": "Asia/Singapore",
"London": "Europe/London",
"Paris": "Europe/Paris",
"Berlin": "Europe/Berlin",
"Moscow": "Europe/Moscow",
"Sydney": "Australia/Sydney",
"Melbourne": "Australia/Melbourne",
}
if normalized, ok := timezoneMap[timezone]; ok {
return normalized
}
// 如果时区有效,直接返回
if isValidTimezone(timezone) {
return timezone
}
// 默认返回 UTC
return carbon.UTC
}
// ConvertTimeToTimezone 将时间字符串转换为指定时区
// 返回转换后的时间字符串
func ConvertTimeToTimezone(timeStr string, timezone string) string {
if timeStr == "" {
return ""
}
// 规范化时区
timezone = NormalizeTimezone(timezone)
// 解析时间字符串
dt := carbon.Parse(timeStr)
if dt.IsZero() {
return timeStr
}
// 转换时区并返回格式化的字符串
return dt.SetTimezone(timezone).ToDateTimeString()
}
// ConvertTimeByContext 根据请求头中的时区转换时间字符串
// 返回转换后的时间字符串
func ConvertTimeByContext(ctx http.Context, timeStr string) string {
if timeStr == "" {
return ""
}
timezone := GetCurrentTimezone(ctx)
return ConvertTimeToTimezone(timeStr, timezone)
}
// ConvertTimeToUTC 将本地时区的时间字符串转换为 UTC 时间字符串(用于数据库查询)
// timeStr: 前端传入的时间字符串(本地时区格式,如 "2025-11-25 14:00:00"
// ctx: 请求上下文,用于获取当前时区
// 返回: UTC 时间字符串(如 "2025-11-25 06:00:00"
func ConvertTimeToUTC(ctx http.Context, timeStr string) string {
if timeStr == "" {
return ""
}
// 获取当前请求的时区
timezone := GetCurrentTimezone(ctx)
// 如果已经是 UTC,直接返回
if timezone == carbon.UTC || timezone == "UTC" {
return timeStr
}
// 加载时区
targetLoc, err := time.LoadLocation(timezone)
if err != nil {
// 如果时区无效,假设是 UTC
return timeStr
}
utcLoc, _ := time.LoadLocation("UTC")
// 解析时间字符串(假设是本地时区格式)
// 尝试多种格式
formats := []string{
utils.DateTimeFormat,
utils.DateTimeFormatT,
utils.DateTimeFormatMs,
utils.DateTimeFormatTZ,
time.RFC3339,
}
var t time.Time
var parseErr error
for _, format := range formats {
t, parseErr = time.ParseInLocation(format, timeStr, targetLoc)
if parseErr == nil {
break
}
}
if parseErr != nil {
// 如果所有格式都失败,尝试使用 carbon 解析
dt := carbon.Parse(timeStr)
if dt.IsZero() {
return timeStr
}
// 假设解析的时间是本地时区,转换为 UTC
return dt.SetTimezone(carbon.UTC).ToDateTimeString()
}
// 转换为 UTC 并格式化
return t.In(utcLoc).Format(utils.DateTimeFormat)
}
// GetTimeQueryParam 获取并转换时间查询参数(统一处理时间查询)
// 自动将前端传入的本地时区时间转换为 UTC 时间用于数据库查询
// 支持常见的时间查询参数名称:start_time, end_time, created_at_start, created_at_end, updated_at_start, updated_at_end
func GetTimeQueryParam(ctx http.Context, paramName string) string {
timeStr := ctx.Request().Query(paramName, "")
if timeStr == "" {
return ""
}
return ConvertTimeToUTC(ctx, timeStr)
}
// FormatTimeWithTimezone 使用指定时区格式化 time.Time
func FormatTimeWithTimezone(t time.Time, timezone string) string {
if t.IsZero() {
return ""
}
if timezone == "" {
timezone = "UTC"
}
loc, err := time.LoadLocation(timezone)
if err != nil {
return t.Format("2006-01-02 15:04:05")
}
return t.In(loc).Format("2006-01-02 15:04:05")
}
// FormatCarbonWithTimezone 使用指定时区格式化 Carbon 时间
func FormatCarbonWithTimezone(t *carbon.DateTime, timezone string) string {
if t == nil || t.IsZero() {
return ""
}
return FormatTimeWithTimezone(t.StdTime(), timezone)
}