220 lines
4.5 KiB
Go
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
|
|
}
|