160 lines
3.6 KiB
Go
160 lines
3.6 KiB
Go
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())
|
|
}
|