timex 处理时间戳

date.go
package timex
import (
"database/sql/driver"
"fmt"
"time"
)
type Date time.Time
func (t *Date) UnmarshalJSON(data []byte) (err error) {
dataTime, err := time.ParseInLocation(`"`+DateFormatter+`"`, string(data), time.Local)
*t = Date(dataTime)
return
}
func (t Date) MarshalJSON() ([]byte, error) {
b := make([]byte, 0, len(DateFormatter)+2)
b = append(b, '"')
b = time.Time(t).AppendFormat(b, DateFormatter)
b = append(b, '"')
return b, nil
}
// Scan valueOf time.Time
func (t *Date) Scan(v any) error {
value, ok := v.(time.Time)
if ok {
*t = Date(value)
return nil
}
return fmt.Errorf("can not convert %T:%v to timestamp", v, v)
}
func (t Date) Value() (driver.Value, error) {
var zeroTime time.Time
if t.UnixNano() == zeroTime.UnixNano() {
return nil, nil
}
return time.Time(t), nil
}
func (t Date) Unix() int64 {
return time.Time(t).Unix()
}
func (t Date) UnixMilli() int64 {
return time.Time(t).UnixMilli()
}
func (t Date) UnixMicro() int64 {
return time.Time(t).UnixMicro()
}
func (t Date) UnixNano() int64 {
return time.Time(t).UnixNano()
}
func (t Date) String() string {
return time.Time(t).Format(DateFormatter)
}
func (t Date) GetTime() time.Time {
return time.Time(t)
}
func (t Date) Compare(t1 Date) int {
return time.Time(t).Compare(time.Time(t1))
}
datetime.go
package timex
import (
"database/sql"
"database/sql/driver"
"fmt"
"time"
)
type DateTime time.Time
func (t *DateTime) UnmarshalJSON(data []byte) (err error) {
dataTime, err := time.ParseInLocation(`"`+DateTimeFormatter+`"`, string(data), time.Local)
*t = DateTime(dataTime)
return
}
func (t DateTime) MarshalJSON() ([]byte, error) {
b := make([]byte, 0, len(DateTimeFormatter)+2)
b = append(b, '"')
b = time.Time(t).AppendFormat(b, DateTimeFormatter)
b = append(b, '"')
return b, nil
}
// Scan valueOf time.Time
func (t *DateTime) Scan(v any) error {
value, ok := v.(time.Time)
if ok {
*t = DateTime(value)
return nil
}
return fmt.Errorf("can not convert %T:%v to timestamp", v, v)
}
func (t DateTime) Value() (driver.Value, error) {
var zeroTime time.Time
if t.UnixNano() == zeroTime.UnixNano() {
return nil, nil
}
return time.Time(t), nil
}
func (t DateTime) Unix() int64 {
return time.Time(t).Unix()
}
func (t DateTime) UnixMilli() int64 {
return time.Time(t).UnixMilli()
}
func (t DateTime) UnixMicro() int64 {
return time.Time(t).UnixMicro()
}
func (t DateTime) UnixNano() int64 {
return time.Time(t).UnixNano()
}
func (t DateTime) String() string {
if time.Time(t).IsZero() {
return ""
}
return time.Time(t).Format(DateTimeFormatter)
}
func (t DateTime) GetTime() time.Time {
return time.Time(t)
}
func (t DateTime) Nullable() NullDateTime {
timeObj := time.Time(t)
if timeObj.IsZero() {
return NullDateTime(sql.NullTime{
Time: timeObj,
Valid: false,
})
}
return NullDateTime(sql.NullTime{
Time: timeObj,
Valid: true,
})
}
func (t DateTime) Compare(t1 DateTime) int {
return time.Time(t).Compare(time.Time(t1))
}
formatters.go
package timex
const (
DateTimeFormatter = "2006-01-02 15:04:05"
DateTimeMilliFormatter = "2006-01-02 15:04:05.000"
DateTimeMicroFormatter = "2006-01-02 15:04:05.000000"
DateFormatter = "2006-01-02"
DateNumberFormatter = "20060102"
DateShortNumberFormatter = "060102"
DateTimeNumFormatter = "20060102150405"
ISO8601DateTimeNumFormatter = "20060102T150405"
)
nullable_datetime.go
package timex
import (
"database/sql"
"database/sql/driver"
"encoding/json"
"time"
)
type NullDateTime sql.NullTime
func (t NullDateTime) MarshalJSON() ([]byte, error) {
if !t.Valid {
return []byte("null"), nil
}
b := make([]byte, 0, len(DateTimeFormatter)+2)
b = append(b, '"')
b = sql.NullTime(t).Time.AppendFormat(b, DateTimeFormatter)
b = append(b, '"')
return b, nil
}
func (t *NullDateTime) UnmarshalJSON(b []byte) error {
if string(b) == "null" {
t.Valid = false
return nil
}
err := json.Unmarshal(b, &t.Time)
if err == nil {
t.Valid = true
}
return err
}
// Scan valueOf time.Time
func (t *NullDateTime) Scan(v any) error {
return (*sql.NullTime)(t).Scan(v)
}
func (t NullDateTime) Value() (driver.Value, error) {
if !t.Valid {
return nil, nil
}
return t.Time, nil
}
func (t NullDateTime) Unix() int64 {
if t.Valid {
return t.Time.Unix()
}
return 0
}
func (t NullDateTime) UnixMilli() int64 {
if t.Valid {
return t.Time.UnixMilli()
}
return 0
}
func (t NullDateTime) UnixMicro() int64 {
if t.Valid {
return t.Time.UnixMicro()
}
return 0
}
func (t NullDateTime) UnixNano() int64 {
if t.Valid {
return t.Time.UnixNano()
}
return 0
}
func (t NullDateTime) String() string {
if sql.NullTime(t).Time.IsZero() {
return ""
}
return sql.NullTime(t).Time.Format(DateTimeFormatter)
}
func (t NullDateTime) GetTime() time.Time {
return t.Time
}
func (t NullDateTime) Compare(t1 NullDateTime) int {
return t.Time.Compare(t1.Time)
}
timestamp.go
package timex
import (
"database/sql/driver"
"fmt"
"strconv"
"time"
)
type TimeStampType string
const (
TimeStampTypeSec TimeStampType = "sec"
TimeStampTypeMilli TimeStampType = "milli"
TimeStampTypeMicro TimeStampType = "micro"
)
// TimeStamp support second or millisecond precision
type TimeStamp struct {
Time time.Time
Stamp int64
Type TimeStampType
Valid bool // Valid is true if Time is not NULL
}
func (t *TimeStamp) UnmarshalJSON(stampByte []byte) (err error) {
*t = TimeStamp{}
if string(stampByte) == "null" {
return nil
}
stamp := string(stampByte)
stampLen := len(stamp)
t.Stamp, err = strconv.ParseInt(stamp, 10, 64)
if err != nil {
return
}
switch {
case stampLen <= 10:
t.Time = time.Unix(t.Stamp, 0)
t.Type = TimeStampTypeSec
case stampLen == 13:
t.Time = time.UnixMilli(t.Stamp)
t.Type = TimeStampTypeMilli
default:
t.Time = time.UnixMicro(t.Stamp)
t.Type = TimeStampTypeMicro
}
t.Valid = true
return
}
func (t TimeStamp) MarshalJSON() ([]byte, error) {
return []byte(strconv.FormatInt(t.Time.Unix(), 10)), nil
}
// Scan valueOf int
func (t *TimeStamp) Scan(v any) error {
*t = TimeStamp{}
ts, ok := v.(int64)
if !ok {
return fmt.Errorf("can not convert %T:%v to timestamp", v, v)
}
if ts <= 0 {
t.Time = time.Time{}
t.Type = TimeStampTypeSec
t.Stamp = ts
t.Valid = false
}
stamp := strconv.FormatInt(ts, 10)
strLen := len(stamp)
switch {
case strLen <= 10:
t.Time = time.Unix(ts, 0)
t.Type = TimeStampTypeSec
case strLen == 13:
t.Time = time.UnixMilli(ts)
t.Type = TimeStampTypeMilli
default:
t.Time = time.UnixMicro(ts)
t.Type = TimeStampTypeMicro
}
t.Stamp = ts
t.Valid = true
return nil
}
func (t TimeStamp) Value() (driver.Value, error) {
if !t.Valid || t.Time.IsZero() {
return nil, nil
}
return t.Time.Unix(), nil
}
func (t TimeStamp) Unix() int64 {
if t.Valid {
return t.Time.Unix()
}
return 0
}
func (t TimeStamp) UnixMilli() int64 {
if t.Valid {
return t.Time.UnixMilli()
}
return 0
}
func (t TimeStamp) UnixMicro() int64 {
if t.Valid {
return t.Time.UnixMicro()
}
return 0
}
func (t TimeStamp) UnixNano() int64 {
if t.Valid {
return t.Time.UnixNano()
}
return 0
}
func (t TimeStamp) String() string {
if !t.Valid || t.Time.IsZero() {
return ""
}
switch t.Type {
case TimeStampTypeSec:
return t.Time.Format(DateTimeFormatter)
case TimeStampTypeMilli:
return t.Time.Format(DateTimeMilliFormatter)
case TimeStampTypeMicro:
fallthrough
default:
return t.Time.Format(DateTimeMicroFormatter)
}
}
func (t TimeStamp) GetTime() time.Time {
return t.Time
}
func (t TimeStamp) Compare(t1 TimeStamp) int {
return t.Time.Compare(t1.Time)
}
timex.go
package timex
import "time"
type Timex[T any] interface {
Unix() int64
UnixMilli() int64
UnixMicro() int64
UnixNano() int64
String() string
GetTime() time.Time
Compare(T) int
}
timex_utils.go
package timex
import (
"database/sql"
"time"
)
type TimeCmd struct {
t time.Time
}
func (cmd TimeCmd) DateTime() DateTime {
return DateTime(cmd.t)
}
func (cmd TimeCmd) Date() Date {
return Date(cmd.t)
}
func (cmd TimeCmd) NullDateTime() NullDateTime {
return NullDateTime(
sql.NullTime{
Time: cmd.t,
Valid: true,
})
}
func (cmd TimeCmd) TimeStamp() TimeStamp {
return TimeStamp{
Time: cmd.t,
Stamp: cmd.t.Unix(),
Type: TimeStampTypeSec,
Valid: true,
}
}
func (cmd TimeCmd) StartOfDay() DateTime {
t := cmd.t
return DateTime(time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()))
}
func (cmd TimeCmd) EndOfDay() DateTime {
t := cmd.t
return DateTime(time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 0, t.Location()))
}
func (cmd TimeCmd) Unix() int64 {
return cmd.t.Unix()
}
func (cmd TimeCmd) UnixMilli() int64 {
return cmd.t.UnixMilli()
}
func (cmd TimeCmd) UnixMicro() int64 {
return cmd.t.UnixMicro()
}
func (cmd TimeCmd) UnixNano() int64 {
return cmd.t.UnixNano()
}
func (cmd TimeCmd) Format(formatter string) string {
return cmd.t.Format(formatter)
}
func (cmd TimeCmd) FormatDateTime() string {
return cmd.t.Format(DateTimeFormatter)
}
func (cmd TimeCmd) FormatDate() string {
return cmd.t.Format(DateFormatter)
}
func (cmd TimeCmd) FormatDateTimeNum() string {
return cmd.t.Format(DateTimeNumFormatter)
}
func Now() TimeCmd {
return TimeCmd{t: time.Now()}
}
func Yesterday() TimeCmd {
return TimeCmd{t: time.Now().AddDate(0, 0, -1)}
}
func Tomorrow() TimeCmd {
return TimeCmd{t: time.Now().AddDate(0, 0, 1)}
}
func StartOfToday() TimeCmd {
now := time.Now()
return TimeCmd{t: time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())}
}
func EndOfToday() TimeCmd {
now := time.Now()
return TimeCmd{t: time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 0, now.Location())}
}
func FromTime(t time.Time) TimeCmd {
return TimeCmd{t: t}
}
func FromFormatterStr(timeStr string, formatters ...string) TimeCmd {
formatter := time.RFC3339
if len(formatters) > 0 {
formatter = formatters[0]
}
t, err := time.Parse(formatter, timeStr)
if err != nil {
t = time.Time{}
}
return TimeCmd{t: t}
}
func FromUnix(second int64) TimeCmd {
return TimeCmd{t: time.Unix(second, 0)}
}
func FromUnixMilli(ms int64) TimeCmd {
return TimeCmd{t: time.UnixMilli(ms)}
}
func FromUnixMicro(ms int64) TimeCmd {
return TimeCmd{t: time.UnixMicro(ms)}
}
func AfterOrEqual(t1, t2 time.Time) bool {
return t1.After(t2) || t1.Equal(t2)
}
func BeforeOrEqual(t1, t2 time.Time) bool {
return t1.Before(t2) || t1.Equal(t2)
}
ts.go
package timex
import (
"database/sql/driver"
"fmt"
"strconv"
"time"
)
type Ts int64
func (t Ts) GetType() TimeStampType {
val := t.GetValue()
switch {
case val < 1e11:
return TimeStampTypeSec
case val < 1e14:
return TimeStampTypeMilli
default:
return TimeStampTypeMicro
}
}
// UnmarshalJSON 从 JSON 字节数组解析时间戳
func (t *Ts) UnmarshalJSON(stampByte []byte) error {
stamp := string(stampByte)
if stamp == "null" {
return nil
}
ts, err := strconv.ParseInt(stamp, 10, 64)
if err != nil {
return err
}
*t = Ts(ZeroOrTs(ts))
return nil
}
// MarshalJSON 将时间戳转换为 JSON 格式
func (t Ts) MarshalJSON() ([]byte, error) {
return []byte(strconv.FormatInt(t.GetValue(), 10)), nil
}
// Scan 从数据库值中扫描时间戳
func (t *Ts) Scan(v any) error {
ts, ok := v.(int64)
if !ok {
return fmt.Errorf("can not convert %T:%v to timestamp", v, v)
}
*t = Ts(ZeroOrTs(ts))
return nil
}
// Value 将时间戳转换为数据库值
func (t Ts) Value() (driver.Value, error) {
return t.GetValue(), nil
}
// Unix 返回秒级时间戳
func (t Ts) Unix() int64 {
return t.GetTime().Unix()
}
// UnixMilli 返回毫秒级时间戳
func (t Ts) UnixMilli() int64 {
return t.GetTime().UnixMilli()
}
// UnixMicro 返回微秒级时间戳
func (t Ts) UnixMicro() int64 {
return t.GetTime().UnixMicro()
}
// UnixNano 返回纳秒级时间戳
func (t Ts) UnixNano() int64 {
return t.GetTime().UnixNano()
}
// String 返回时间戳的字符串表示
func (t Ts) String() string {
if !t.IsValid() {
return "0"
}
time := t.GetTime()
switch t.GetType() {
case TimeStampTypeSec:
return time.Format(DateTimeFormatter)
case TimeStampTypeMilli:
return time.Format(DateTimeMilliFormatter)
case TimeStampTypeMicro:
fallthrough
default:
return time.Format(DateTimeMicroFormatter)
}
}
func (t Ts) GetTime() time.Time {
switch t.GetType() {
case TimeStampTypeSec:
return time.Unix(t.GetValue(), 0)
case TimeStampTypeMilli:
return time.UnixMilli(t.GetValue())
case TimeStampTypeMicro:
return time.UnixMicro(t.GetValue())
default:
return time.Time{}
}
}
func (t Ts) IsValid() bool {
return t > 0
}
func (t Ts) GetValue() int64 {
return ZeroOrTs(int64(t))
}
func ZeroOrTs(ts int64) int64 {
if ts <= 0 {
// TODO: 目前不处理负数时间戳,后续可以优化
ts = 0
}
return ts
}
func (t Ts) Compare(t1 Ts) int {
return t.GetTime().Compare(t1.GetTime())
}
type TsMilli Ts
// MarshalJSON 将时间戳转换为 JSON 格式
func (t TsMilli) MarshalJSON() ([]byte, error) {
return []byte(strconv.FormatInt(Ts(t).UnixMilli(), 10)), nil
}
// Value 将时间戳转换为数据库值
func (t TsMilli) Value() (driver.Value, error) {
return Ts(t).UnixMilli(), nil
}
// String 返回时间戳的字符串表示
func (t TsMilli) String() string {
if t <= 0 {
return "0"
}
return (Ts(t).GetTime()).Format(DateTimeMilliFormatter)
}
type TsMicro Ts
// MarshalJSON 将时间戳转换为 JSON 格式
func (t TsMicro) MarshalJSON() ([]byte, error) {
return []byte(strconv.FormatInt(Ts(t).UnixMicro(), 10)), nil
}
// Value 将时间戳转换为数据库值
func (t TsMicro) Value() (driver.Value, error) {
return Ts(t).UnixMicro(), nil
}
// String 返回时间戳的字符串表示
func (t TsMicro) String() string {
if t <= 0 {
return "0"
}
return (Ts(t).GetTime()).Format(DateTimeMicroFormatter)
}

浙公网安备 33010602011771号