golang中处理接口中的时间(created_at等)

golang中的time采用的是rfc3339时间协议,mgo.v2不能直接将time.Time类型的字段存入mongodb中 ,同样也不方便将mongo存储的timestamp转为time.Timer。因此,需要实现一个自定义的时间类型BsonTime。为了能够对mgo.v2的序列化支持,需要实现标准库中的Unmarshaler接口。实现了该接口能够将mongodb和golang的时间戳打通,还够将BsonTime类型的时间在toJson的时候转为常用的时间字符串。

对api接口中传入的时间戳,可以使用mapstructure和实现自定义的Decode函数实现解析,将时间戳、事件字符串转为自定义的BsonTime

在线运行地址:https://play.golang.org/p/nciTC7rdYZC

自定义BsonTime,将golang的time.Time存入mongodb中

const timeFormart = "2006-01-02 15:04:05"

// 对struct增加 MarshalJSON ,UnmarshalJSON , String 方法,实现自定义json输出格式与打印方式
type BsonTime struct {
	time.Time
}

func (t BsonTime) String() string {
	return t.Time.Format(timeFormart)
}

// 实现它的json序列化方法
func (t BsonTime) MarshalJSON() ([]byte, error) {
	var stamp = fmt.Sprintf("\"%s\"", t.Time.Format("2006-01-02 15:04:05"))
	return []byte(stamp), nil
}

func (t *BsonTime) UnmarshalJSON(data []byte) error {
	if err := t.Time.UnmarshalJSON(data); err != nil {
		return err
	}
	return nil
}

func (t BsonTime) GetBSON() (interface{}, error) {
	if t.IsZero() {
		return nil, nil
	}
	return t.Time, nil
}

func (t *BsonTime) SetBSON(raw bson.Raw) error {
	var tm time.Time
	if err := raw.Unmarshal(&tm); err != nil {
		return err
	}
	t.Time = tm
	return nil
}

利用mapstructure库提供的自定义Decode函数,对struct中的BsonTime字段使用自定义的Decode方法。

func ToTimeHookFunc() mapstructure.DecodeHookFunc {
	return func(
		f reflect.Type,
		t reflect.Type,
		data interface{}) (interface{}, error) {
		if !reflect.DeepEqual(t, reflect.TypeOf(BsonTime{})) {
			return data, nil
		}
		var tTime time.Time
		var err error
		switch f.Kind() {
		case reflect.String:
			tTime, err = time.Parse("2006-01-02 15:04:05", data.(string))
		case reflect.Float64:
			tTime, err = time.Unix(0, int64(data.(float64))*int64(time.Millisecond)), nil
		case reflect.Int64:
			tTime, err = time.Unix(0, data.(int64)*int64(time.Millisecond)), nil
		default:
			return data, nil
		}
		if err != nil {
			return nil, err
		}
		return BsonTime{
			Time: tTime,
		}, nil
	}
}

// Map2StructWithBsonTime user `mapstructure` convert map to struct, with process time to BsonTime.
func Map2StructWithBsonTime(input map[string]interface{}, result interface{}) error {
	decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
		Metadata:   nil,
		DecodeHook: mapstructure.ComposeDecodeHookFunc(ToTimeHookFunc()),
		Result:     result,
		TagName:    "json",
	})
	if err != nil {
		return err
	}
	if err := decoder.Decode(input); err != nil {
		return err
	}
	return nil
}

使用

import (
	"encoding/json"
	"fmt"
	"github.com/globalsign/mgo/bson"
	"github.com/mitchellh/mapstructure"
	"log"
	"reflect"
	"time"
)
var rawStr = `
{
    "created_by": "7290310f-3574-4520-9ef1-79188bc7c997",
    "created_time": 1563884700000,
    "last_edited_time": 1563884700000,
    "last_edited_by": "7290310f-3574-4520-9ef1-79188bc7c997",
    "last_reply_at": "2019-07-01 12:34:56"
}
`

// AuthorTime must define `JSON TAG`.
type AuthorTime struct {
	CreatedBy   string   `json:"created_by"`
	CreatedAt   BsonTime `json:"created_time"`
	UpdatedBy   string   `json:"last_edited_by"`
	UpdatedAt   BsonTime `json:"last_edited_time"`
	LastReplyAt BsonTime `json:"last_reply_at"`
}

func main() {
	var paramsBind map[string]interface{}              // 模拟gin的参数绑定
	err := json.Unmarshal([]byte(rawStr), ¶msBind) //paramsBind需要是引用类型
	if err != nil {
		panic(err)
	}

	// 将参数转化为struct
	var author AuthorTime
	err = Map2StructWithBsonTime(paramsBind, &author)
	if err != nil {
		panic(err)
	}

	// 转为json
	toJson, err := json.Marshal(&author)
	if err != nil {
		panic(err)
	}
	log.Println(string(toJson))
}

你可能感兴趣的:(golang)