前言
因为时区等问题,很多项目需要自定义时区和时间格式。还有需要自定义输出显示。
方案
代码
package timetool import ( "database/sql/driver" "fmt" "time" ) const TimeFormat = "2006-01-02 15:04:05" const FormatISOTime = "2006-01-02T15:04:05Z" const DayFormat = "20060102" const SecondDateFormat = "20060102150405" const FYear = "2006" //年 const FMonth = "01" //月 const FMonthNoZero = "1" //月,不带先导零 const FDay = "02" //日 const FDayNoZero = "2" //日,不带先导零 const FHour = "15" // 小时,24小时格式 const FMinute = "04" // 分钟 const FSecond = "05" // 秒 // 1. 创建 time.Time 类型的副本 XTime; type MyTime struct { time.Time } // 2. 为 MyTime 重写 MarshaJSON 方法,在此方法中实现自定义格式的转换; func (t MyTime) MarshalJSON() ([]byte, error) { loc := time.FixedZone(pkg.TimeLocal.TimeZone, pkg.TimeLocal.TimeOffset) output := fmt.Sprintf("\"%s\"", t.In(loc).Format(TimeFormat)) return []byte(output), nil } // 3. 为 MyTime 实现 Value 方法,写入数据库时会调用该方法将自定义时间类型转换并写入数据库; func (t MyTime) Value() (driver.Value, error) { var zeroTime time.Time if t.Time.UnixNano() == zeroTime.UnixNano() { return nil, nil } return t.Time, nil } // 4. 为 MyTime 实现 Scan 方法,读取数据库时会调用该方法将时间数据转换成自定义时间类型; func (t *MyTime) Scan(v interface{}) error { value, ok := v.(time.Time) if ok { *t = MyTime{Time: value} return nil } return fmt.Errorf("can not convert %v to timestamp", v) } func (t *MyTime) String() string { loc := time.FixedZone(pkg.TimeLocal.TimeZone, pkg.TimeLocal.TimeOffset) return t.In(loc).String() } func (t *MyTime) GetTime() time.Time { loc := time.FixedZone(pkg.TimeLocal.TimeZone, pkg.TimeLocal.TimeOffset) return t.In(loc) } func (t *MyTime) UnmarshalJSON(data []byte) (err error) { // 空值不进行解析 if len(data) == 2 { return } if string(data) == "null" { return } var now time.Time // 指定解析的格式 if now, err = time.ParseInLocation(TimeFormat, string(data), time.Local); err == nil { *t = MyTime{now} return } // 指定解析的格式 if now, err = time.ParseInLocation('"'+TimeFormat+'"', string(data), time.Local); err == nil { *t = MyTime{now} return } //解析默认格式 if now, err = time.ParseInLocation('"'+time.RFC3339+'"', string(data), time.Local); err == nil { *t = MyTime{now} return } return } func MyTimeNow() MyTime { return MyTime{Time: time.Now()} } func NewMyTime(ts ...int64) *MyTime { if len(ts) == 0 { return &MyTime{Time: time.Now()} } loc := time.FixedZone(pkg.TimeLocal.TimeZone, pkg.TimeLocal.TimeOffset) return &MyTime{ Time: time.Unix(ts[0], 0).In(loc), } }
注意:
JSON 关键点:
- 实现 MarshalJSON 方法
- 实现 UnmarshalJSON 方法
- 实现 Value 方法
Gorm关键点:
- 实现 Scan 方法
- 实现 String 方法