package types import ( "database/sql" "database/sql/driver" "encoding/json" "fmt" "time" "go.uber.org/zap" ) var ( dateLayouts = []string{ "2006-01-02", "2006-1-2", "2006/01/02", "06-1-2", "6-01-02", "01/02/06", "1/2/06", "2006年01月02日", "06年1月2日", } ) // 封装日期类型。 type Date struct { time.Time } // 根据给定的年月日创建一个日期类型实例。 func NewDate(year int, month time.Month, day int) Date { return Date{ Time: time.Date(year, month, day, 0, 0, 0, 0, loc), } } // 创建一个新的空白日期类型实例。 func NewEmptyDate() Date { return Date{ Time: time.Time{}.In(loc), } } // 获取当前日期。 func NowDate() Date { return Now().Date() } // 从给定的字符串中解析日期。如果无法解析则返回错误。 func ParseDate(t string) (Date, error) { if len(t) == 0 { return NewEmptyDate(), fmt.Errorf("不能解析空白的日期时间。") } for _, layout := range dateLayouts { d, err := time.ParseInLocation(layout, t, loc) if err == nil { return Date{ Time: d, }, nil } } return NewEmptyDate(), fmt.Errorf("无法解析给定的日期,格式不正确。") } // 尝试从字符串中解析日期,如果无法解析则返回给定的默认值。 func ParseDateWithDefault(t string, defaultDate Date) Date { if len(t) == 0 { return defaultDate } d, err := ParseDate(t) if err != nil { return defaultDate } return d } var _ driver.Valuer = (*Date)(nil) func (dt Date) Value() (driver.Value, error) { return dt.In(loc).Format("2006-01-02"), nil } var _ sql.Scanner = (*Date)(nil) func (d *Date) Scan(src interface{}) (err error) { switch src := src.(type) { case time.Time: d.Time = src case string: t, err := time.ParseInLocation("2006-01-02", src, loc) if err != nil { return err } *d = Date{Time: t} case []byte: d.Time, err = time.ParseInLocation("2006-01-02", string(src), loc) return err case nil: d = nil default: return fmt.Errorf("该数据类型不支持解析到日期: %T", src) } return nil } var _ json.Marshaler = (*Date)(nil) func (d Date) MarshalJSON() ([]byte, error) { return json.Marshal(d.Format("2006-01-02")) } var _ json.Unmarshaler = (*Date)(nil) func (d *Date) UnmarshalJSON(data []byte) error { var str string if err := json.Unmarshal(data, &str); err != nil { return fmt.Errorf("不能解析指定的日期时间值: %w", err) } t, err := time.ParseInLocation("2006-01-02", str, loc) d.Time = t return err } // 计算两个日期之间的月份差。 func (d Date) DifferenceInMonth(d2 *Date) int { var differYear, differMonth int differYear = d.Year() - d2.Year() differMonth = int(d.Month() - d2.Month()) return differYear*12 + differMonth } // 判断给定日期是否是当前日期的下一个月。 func (d Date) IsNextMonth(d2 *Date) bool { return d.DifferenceInMonth(d2) == 1 } // 获取当前日期的最开始时间。 func (d Date) ToBeginningOfDate() DateTime { return FromTime(time.Date(d.Year(), d.Month(), d.Day(), 0, 0, 0, 0, loc)) } // 获取当前日期的最末尾时间。 func (d Date) ToEndingOfDate() DateTime { return FromTime(time.Date(d.Year(), d.Month(), d.Day(), 23, 59, 59, 999999, loc)) } // 判断当前日期是否为空白日期。 func (d Date) IsEmpty() bool { return d.Time.IsZero() } // 使用`YYYY-MM-DD`格式输出日期。 func (d Date) ToString() string { return d.Time.Format("2006-01-02") } // 将当前日期转换为日期时间类型。 func (d Date) ToDateTime() DateTime { return FromTime(d.Time) } // 在Zap日志中以给定的`fieldName`为字段名输出日期。 func (d Date) Log(fieldName string) zap.Field { return zap.String(fieldName, d.ToString()) }