最近開發一個公司專案,發現Go語言結構體Json轉換時,存在時間格式不一樣問題。在網上找了很久也沒有找到一個很好的方案。即結構體序列化後的格式是`1993-01-01T20:08:23.000000028+08:00`。但為了相容公司以往的專案,希望沿用`1993-01-01 20:08:23`這種格式。網上找到了下面的程式碼,可以解決大部分的問題。
import "time"
const (
DateFormat = "2006-01-02"
TimeFormat = "2006-01-02 15:04:05"
)
type Time time.Time
func Now() Time {
return Time(time.Now())
}
func (t *Time) UnmarshalJSON(data []byte) (err error) {
now, err := time.ParseInLocation(`"`+TimeFormat+`"`, string(data), time.Local)
*t = Time(now)
return
}
func (t Time) MarshalJSON() ([]byte, error) {
b := make([]byte, 0, len(TimeFormat)+2)
b = append(b, `"`)
b = time.Time(t).AppendFormat(b, TimeFormat)
b = append(b, `"`)
return b, nil
}
func (t Time) String() string {
return time.Time(t).Format(TimeFormat)
}
但是這樣寫會對原有的struct產生影響,需要將原來的time.Time的變數型別替換成Time。可在使用一些ORM時就不行了,比如Beego的Orm就會報錯了。因此,要在不改變結構體時間型別的情況下,替換掉原來的時間格式。就只能和上面的程式碼一樣,給結構體也實現MarshalJson和UnmarshalJson方法。
type User struct {
Id int `json:"id"`
Name string `json:"name"`
CreatedAt time.Time `json:"created_at"`
}
func (u *User) MarshalJSON() ([]byte, error) {
type Alias User
user := &struct {
CreatedAt Time `json:"created_at"`
*Alias
}{Time(u.CreatedAt), (*Alias)(u)}
return json.Marshal(user)
}
func (u *User) UnmarshalJSON(data []byte) (err error) {
type Alias User
user := &struct {
CreatedAt Time `json:"created_at"`
*Alias
}{Time(u.CreatedAt), (*Alias)(u)}
err = json.Unmarshal(data, user)
if err != nil {
return err
}
user.Alias.CreatedAt = time.Time(user.CreatedAt)
*u = User(*user.Alias)
return nil
}
func main() {
var user *User
user = &User{
Id: 4,
Name: "Liam",
CreatedAt: time.Now(),
}
bytes, _ := json.Marshal(user)
fmt.Printf("%v
", string(bytes))
data := `{"id":3, "name":"Liam Lian", "created_at":"2017-11-18 19:00:00"}`
json.Unmarshal([]byte(data), &user)
fmt.Printf("%v
", user)
}
雖然這樣便實現了時間格式的相容,而且不影響原來的結構體。但如果這樣的結構體比較多的話,就會有很多的這類程式碼。於是就要用其他json包了。如liamylian/jsontime
package main
import(
"fmt"
"time"
"github.com/liamylian/jsontime"
)
var json = jsontime.ConfigWithCustomTimeFormat
type User struct {
Id int `json:"id"`
Name string `json:"name"`
CreatedAt time.Time `json:"created_at" time_format:"sql_datetime" time_utc:"false"`
}
func main() {
user := User {
Id: 1,
Name: "Liam",
CreatedAt: time.Now(),
}
bytes, _ := json.Marshal(user)
fmt.Printf("%s", bytes)
}