Files
2026-08-26 17:32:54 +08:00

220 lines
4.5 KiB
Go

package utils
import (
"database/sql/driver"
"fmt"
"strings"
"time"
"gorm.io/gorm"
"gorm.io/gorm/schema"
)
var AsiaShanghai *time.Location
func init() {
var err error
AsiaShanghai, err = time.LoadLocation("Asia/Shanghai")
if err != nil {
AsiaShanghai = time.FixedZone("CST", 8*3600)
}
}
// CustomTime 自定义时间类型
type CustomTime struct {
time.Time
}
func GetAfterMinutes(minutes int) CustomTime {
t := time.Now().In(AsiaShanghai).Add(time.Duration(minutes) * time.Minute)
return CustomTime{Time: t}
}
// Now 获取当前时间
func Now() CustomTime {
return CustomTime{time.Now().In(AsiaShanghai)}
}
// Format 返回 yyyy-mm-dd H:i:s 格式字符串
func (ct CustomTime) Format(layouts ...string) string {
if ct.IsZero() {
return ""
}
layout := time.DateTime // 默认格式:2006-01-02 15:04:05
if len(layouts) > 0 && layouts[0] != "" {
layout = layouts[0]
}
return ct.Time.Format(layout)
}
// String 实现 Stringer 接口
// func (ct CustomTime) String() string {
// return ct.Format()
// }
func (ct CustomTime) String() string {
if ct.Time.IsZero() {
return ""
}
return ct.Time.Format(time.DateTime)
}
// MarshalJSON 实现 JSON 序列化
func (ct CustomTime) MarshalJSON() ([]byte, error) {
if ct.IsZero() {
return []byte("null"), nil
}
return []byte(`"` + ct.Format() + `"`), nil
}
// UnmarshalJSON 实现 JSON 反序列化
func (ct *CustomTime) UnmarshalJSON(data []byte) error {
str := string(data)
if str == "null" || str == `""` {
ct.Time = time.Time{}
return nil
}
// 去除引号
str = strings.Trim(str, `"`)
// 尝试解析多种格式
formats := []string{
"2006-01-02",
"2006-01-02 15:04:05",
"2006-01-02T15:04:05Z07:00",
time.RFC3339,
time.RFC3339Nano,
}
var err error
for _, layout := range formats {
ct.Time, err = time.Parse(layout, str)
if err == nil {
return nil
}
}
return fmt.Errorf("invalid time format: %s", str)
}
// Value 实现 driver.Valuer 接口 (数据库写入)
func (ct CustomTime) Value() (driver.Value, error) {
if ct.IsZero() {
return nil, nil
}
return ct.Time, nil
}
// Scan 实现 sql.Scanner 接口 (数据库读取)
func (ct *CustomTime) Scan(value interface{}) error {
if value == nil {
ct.Time = time.Time{}
return nil
}
switch v := value.(type) {
case time.Time:
ct.Time = v
return nil
case []byte:
return ct.UnmarshalJSON(v)
case string:
return ct.UnmarshalJSON([]byte(v))
default:
return fmt.Errorf("unsupported type: %T", value)
}
}
// GormDataType 定义 GORM 数据库类型
func (CustomTime) GormDataType() string {
return "datetime"
}
// GormDBDataType 定义 GORM 数据库类型 (v2 版本)
func (CustomTime) GormDBDataType(db *gorm.DB, field *schema.Field) string {
switch db.Dialector.Name() {
case "mysql", "sqlite":
return "datetime"
case "postgres":
return "timestamp"
default:
return "datetime"
}
}
func ParseTime(s string) (time.Time, error) {
formats := []string{
"2006-01-02",
"2006-01-02 15:04:05",
}
var t time.Time
var err error
for _, layout := range formats {
t, err = time.ParseInLocation(layout, s, time.Local)
if err == nil {
return t, nil
}
}
return time.Time{}, fmt.Errorf("invalid time format: %s", s)
}
func dayBoundary(s string, h, m, sec int) (CustomTime, error) {
t, err := ParseTime(s)
if err != nil {
return CustomTime{}, err
}
return CustomTime{
Time: time.Date(t.Year(), t.Month(), t.Day(), h, m, sec, 0, t.Location()),
}, nil
}
func TimeStart(day int, timeStr string) string {
// 2. 格式化开始时间:前一天 23:59:59
startTime, err := time.Parse(time.DateOnly, timeStr)
if err == nil {
startTime = startTime.Add(time.Duration(-24*day) * time.Hour) // 减N天
startResult := startTime.Format(time.DateOnly)
return startResult + " 23:59:59"
}
return ""
}
func TimeEnd(day int, timeStr string) string {
endTime, err := time.Parse(time.DateOnly, timeStr)
if err == nil {
endTime = endTime.Add(time.Duration(+24*day) * time.Hour) // 加一天
endResult := endTime.Format(time.DateTime)
return endResult
}
return ""
}
func TimeToUnix(timeStr string, layout string) (int64, error) {
t, err := time.ParseInLocation(layout, timeStr, time.FixedZone("CST", 8*3600))
if err != nil {
Logger.Error(err)
return 0, err
}
// 转 11 位时间戳(秒)
return t.Unix(), nil
}
func ParseCustomTime(s string) (CustomTime, error) {
ct := CustomTime{}
// UnmarshalJSON 需要带双引号的json字符串,所以包装成json字符串格式
err := ct.UnmarshalJSON([]byte(`"` + s + `"`))
if err != nil {
return CustomTime{}, err
}
return ct, nil
}