Files
lone-services/pkg/utils/time.go
T
zzw b77a1f1b95
CI / changes (push) Successful in 1m31s
CI / ad (push) Successful in 32s
CI / admin (push) Successful in 26s
CI / analysis (push) Successful in 28s
CI / bff (push) Successful in 23s
CI / chore (push) Successful in 24s
CI / equipment (push) Successful in 21s
CI / express (push) Successful in 21s
CI / factory (push) Successful in 18s
CI / message (push) Successful in 18s
CI / order (push) Successful in 21s
CI / payment (push) Successful in 20s
CI / percutaneous (push) Successful in 19s
CI / product (push) Successful in 21s
CI / record (push) Successful in 21s
CI / sale (push) Successful in 20s
CI / store (push) Successful in 25s
CI / support (push) Successful in 21s
CI / task (push) Successful in 20s
CI / user (push) Successful in 22s
CI / water (push) Successful in 20s
CI / wecom (push) Successful in 21s
CI / ws (push) Successful in 8s
feat: user improve
2026-10-27 13:01:24 +08:00

254 lines
5.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 := strings.Trim(string(data), `"`)
if str == "" || str == "null" || isZeroDate(str) {
ct.Time = time.Time{}
return nil
}
// 尝试解析多种格式
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.scanString(string(v))
case string:
return ct.scanString(v)
default:
return fmt.Errorf("unsupported type: %T", value)
}
}
func (ct *CustomTime) scanString(s string) error {
s = strings.TrimSpace(s)
if s == "" || isZeroDate(s) {
ct.Time = time.Time{}
return nil
}
return ct.UnmarshalJSON([]byte(`"` + s + `"`))
}
func isZeroDate(s string) bool {
return s == "0000-00-00" || s == "0000-00-00 00:00:00"
}
// 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
}
// ParseDateOnly 解析 YYYY-MM-DD;兼容带时间的字符串,只取日期部分;空串返回零值(写入 DB 为 NULL)
func ParseDateOnly(s string) (CustomTime, error) {
s = strings.TrimSpace(s)
if s == "" || isZeroDate(s) {
return CustomTime{}, nil
}
if len(s) >= len(time.DateOnly) {
s = s[:len(time.DateOnly)]
}
t, err := time.ParseInLocation(time.DateOnly, s, AsiaShanghai)
if err != nil {
return CustomTime{}, fmt.Errorf("invalid date format: %s", s)
}
return CustomTime{Time: t}, nil
}
// DateString 返回 YYYY-MM-DD;零值返回空串
func (ct CustomTime) DateString() string {
if ct.IsZero() {
return ""
}
return ct.Time.Format(time.DateOnly)
}