feat(types):增加日期时间类型。
This commit is contained in:
parent
23293b6d27
commit
539e4ec384
|
@ -20,6 +20,7 @@ Golang 中可以使用的常用辅助功能工具箱。主要配备以下功能
|
|||
- [ ] 1024 位长
|
||||
- [ ] 2048 位长
|
||||
- [ ] KeyPair 生成器
|
||||
- [ ] RSA 签名算法
|
||||
- 散列算法。
|
||||
- [ ] Sha512 散列算法
|
||||
- [ ] Sha256 散列算法
|
||||
|
@ -30,8 +31,6 @@ Golang 中可以使用的常用辅助功能工具箱。主要配备以下功能
|
|||
- [ ] 冰雹 ID 生成器(短主机精简日期版雪花 ID)
|
||||
- [ ] UUID 生成器
|
||||
- [ ] short UUID 生成器
|
||||
- 签名算法
|
||||
- [ ] RSA 签名算法
|
||||
- 验证码生成器
|
||||
- [ ] 随机验证码生成算法
|
||||
- 序列化算法
|
||||
|
|
7
go.mod
7
go.mod
|
@ -1,3 +1,10 @@
|
|||
module archgrid.xyz/ag/toolsbox
|
||||
|
||||
go 1.20
|
||||
|
||||
require go.uber.org/zap v1.24.0
|
||||
|
||||
require (
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
)
|
||||
|
|
11
go.sum
Normal file
11
go.sum
Normal file
|
@ -0,0 +1,11 @@
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
159
types/date.go
Normal file
159
types/date.go
Normal file
|
@ -0,0 +1,159 @@
|
|||
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())
|
||||
}
|
167
types/datetime.go
Normal file
167
types/datetime.go
Normal file
|
@ -0,0 +1,167 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var (
|
||||
loc *time.Location = time.FixedZone("+0800", 8*60*60)
|
||||
datetimeLayouts = []string{
|
||||
"2006-01-02 15:04:05", "2006-1-2 15:04:05", "2006/01/02 15:04:05", "06-1-2 15:04:05", "06-01-02 15:04:05", "01/02/06 15:04:05", "1/2/06 15:04:05", "2006年01月02日 15:04:05", "06年1月2日 15:04:05",
|
||||
"2006-01-02 15:04", "2006-1-2 15:04", "2006/01/02 15:04", "06-1-2 15:04", "06-01-02 15:04", "01/02/06 15:04", "1/2/06 15:04", "2006年01月02日 15:04", "06年1月2日 15:04",
|
||||
}
|
||||
)
|
||||
|
||||
// 封装日期时间类型。
|
||||
type DateTime struct {
|
||||
time.Time
|
||||
}
|
||||
|
||||
// 获取当前的日期时间。
|
||||
func Now() DateTime {
|
||||
return DateTime{
|
||||
Time: time.Now().In(loc),
|
||||
}
|
||||
}
|
||||
|
||||
// 创建一个空白的日期时间类型实例。
|
||||
func NewEmptyDateTime() DateTime {
|
||||
return DateTime{
|
||||
Time: time.Time{}.In(loc),
|
||||
}
|
||||
}
|
||||
|
||||
// 获取一个自`2022-02-22 22:22:22.0`以来的秒数时间戳。
|
||||
func Timestamp() int64 {
|
||||
startline := time.Date(2022, 2, 22, 22, 22, 22, 0, loc).Unix()
|
||||
return Now().Unix() - startline
|
||||
}
|
||||
|
||||
// 从指定的字符串中解析日期时间。如果无法解析则返回错误。
|
||||
func ParseDateTime(t string) (DateTime, error) {
|
||||
if len(t) == 0 {
|
||||
return NewEmptyDateTime(), fmt.Errorf("不能解析空白的日期时间。")
|
||||
}
|
||||
for _, layout := range datetimeLayouts {
|
||||
fmt.Printf("Parse: %s, Try layout: %s\n", t, layout)
|
||||
d, err := time.ParseInLocation(layout, t, loc)
|
||||
if err == nil {
|
||||
return DateTime{
|
||||
Time: d,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
return NewEmptyDateTime(), fmt.Errorf("无法解析给定的日期时间,格式不正确。")
|
||||
}
|
||||
|
||||
// 封装一个标准库中的时间类型。
|
||||
func FromTime(t time.Time) DateTime {
|
||||
return DateTime{
|
||||
Time: t,
|
||||
}
|
||||
}
|
||||
|
||||
// 解析一个Unix时间戳。
|
||||
func FromUnixMicro(sec int64) DateTime {
|
||||
return DateTime{
|
||||
Time: time.UnixMicro(sec).In(loc),
|
||||
}
|
||||
}
|
||||
|
||||
var _ driver.Valuer = (*DateTime)(nil)
|
||||
|
||||
func (dt DateTime) Value() (driver.Value, error) {
|
||||
return dt.In(loc).Format("2006-01-02 15:04:05"), nil
|
||||
}
|
||||
|
||||
var _ sql.Scanner = (*DateTime)(nil)
|
||||
|
||||
func (dt *DateTime) Scan(src interface{}) (err error) {
|
||||
switch src := src.(type) {
|
||||
case time.Time:
|
||||
dt.Time = src
|
||||
case string:
|
||||
t, err := time.ParseInLocation("2006-01-02 15:04:05", src, loc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*dt = DateTime{Time: t}
|
||||
case []byte:
|
||||
dt.Time, err = time.ParseInLocation("2006-01-02 15:04:05", string(src), loc)
|
||||
return err
|
||||
case nil:
|
||||
dt = nil
|
||||
default:
|
||||
return fmt.Errorf("该数据类型不支持解析到日期时间: %T", src)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ json.Marshaler = (*DateTime)(nil)
|
||||
|
||||
func (dt DateTime) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(dt.Format("2006-01-02 15:04:05"))
|
||||
}
|
||||
|
||||
var _ json.Unmarshaler = (*DateTime)(nil)
|
||||
|
||||
func (dt *DateTime) 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 15:04:05", str, loc)
|
||||
dt.Time = t
|
||||
return err
|
||||
}
|
||||
|
||||
// 计算给定日期时间与当前日期时间的月份差值。
|
||||
func (dt DateTime) DifferenceInMonth(d DateTime) int {
|
||||
var differYear, differMonth int
|
||||
differYear = dt.Year() - d.Year()
|
||||
differMonth = int(dt.Month() - d.Month())
|
||||
return differYear*12 + differMonth
|
||||
}
|
||||
|
||||
// 判断给定日期时间是否是当前日期时间的下一个月。
|
||||
func (dt DateTime) IsNextMonth(target DateTime) bool {
|
||||
return dt.DifferenceInMonth(target) == 1
|
||||
}
|
||||
|
||||
// 将当前日期时间调整为当天的开始时间。
|
||||
func (dt *DateTime) ToBeginningOfDate() {
|
||||
dt.Time = time.Date(dt.Year(), dt.Month(), dt.Day(), 0, 0, 0, 0, loc)
|
||||
}
|
||||
|
||||
// 将当前日期时间调整为当天的结束时间。
|
||||
func (dt *DateTime) ToEndingOfDate() {
|
||||
dt.Time = time.Date(dt.Year(), dt.Month(), dt.Day(), 23, 59, 59, 999999, loc)
|
||||
}
|
||||
|
||||
// 从当前日期时间中获取日期部分。
|
||||
func (dt DateTime) Date() Date {
|
||||
return Date{
|
||||
Time: time.Date(dt.Year(), dt.Month(), dt.Day(), 0, 0, 0, 0, loc),
|
||||
}
|
||||
}
|
||||
|
||||
// 判断当前日期时间是否为空。
|
||||
func (dt DateTime) IsEmpty() bool {
|
||||
return dt.Time.IsZero()
|
||||
}
|
||||
|
||||
// 以`YYYY-MM-DD HH:mm:ss`格式输出日期时间。
|
||||
func (dt DateTime) ToString() string {
|
||||
return dt.Time.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
// 在Zap日志中以给定`fieldName`为字段名输出日期时间。
|
||||
func (dt DateTime) Log(fieldName string) zap.Field {
|
||||
return zap.String(fieldName, dt.ToString())
|
||||
}
|
2
types/types.go
Normal file
2
types/types.go
Normal file
|
@ -0,0 +1,2 @@
|
|||
// 定义常用的数据类型,包括数据类型在数据库内的存储和读取,以及数据类型在JSON格式中的输出与解析。
|
||||
package types
|
Loading…
Reference in New Issue
Block a user