如何在发送的 JSON 中格式化时间戳?

huangapple go评论101阅读模式
英文:

How to format timestamp in outgoing JSON

问题

我最近一直在使用Go语言,它非常棒。但有一件事我似乎无法弄清楚(在查阅文档和博客文章之后),就是如何在使用json.NewEncoder.Encode进行编码时,将time.Time类型的数据格式化为我想要的任意格式。

这是一个简单的代码示例:

package main

type Document struct {
    Name        string
    Content     string
    Stamp       time.Time
    Author      string
}

func sendResponse(data interface{}, w http.ResponseWriter, r * http.Request){
     _, err := json.Marshal(data)
    j := json.NewEncoder(w)
    if err == nil {
        encodedErr := j.Encode(data)
        if encodedErr != nil{
            //code snipped
        }
    }else{
       //code snipped
    }
}

func main() {
    http.HandleFunc("/document", control.HandleDocuments)
    http.ListenAndServe("localhost:4000", nil)
}

func HandleDocuments(w http.ResponseWriter,r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    w.Header().Set("Access-Control-Allow-Origin", "*")

    switch r.Method {
        case "GET": 
            //logic snipped
            testDoc := model.Document{"Meeting Notes", "These are some notes", time.Now(), "Bacon"}    
            sendResponse(testDoc, w,r)
            }
        case "POST":
        case "PUT":
        case "DELETE":
        default:
            //snipped
    }
}

理想情况下,我希望发送一个请求,并将Stamp字段返回为类似于May 15, 2014而不是2014-05-16T08:28:06.801064-04:00的格式。

但我真的不知道如何做到这一点,我知道我可以在Document类型声明中添加json:stamp,以使该字段被编码为stamp而不是Stamp,但我不知道这些类型的东西叫什么,所以我甚至不知道要搜索什么来了解是否有某种格式选项。

有没有人有关于这些类型标记(或者它们被称为什么)的示例或好的文档页面的链接,或者关于如何告诉JSON编码器处理time.Time字段的文档?

供参考,我已经查看了这些页面:这里这里,当然还有官方文档

英文:

I've been playing with Go recently and it's awesome. The thing I can't seem to figure out (after looking through documentation and blog posts) is how to get the time.Time type to format into whatever format I'd like when it's encoded by json.NewEncoder.Encode

Here's a minimal Code example:

package main

type Document struct {
    Name        string
    Content     string
    Stamp       time.Time
    Author      string
}

func sendResponse(data interface{}, w http.ResponseWriter, r * http.Request){
     _, err := json.Marshal(data)
    j := json.NewEncoder(w)
    if err == nil {
        encodedErr := j.Encode(data)
        if encodedErr != nil{
            //code snipped
        }
    }else{
       //code snipped
    }
}

func main() {
    http.HandleFunc("/document", control.HandleDocuments)
    http.ListenAndServe("localhost:4000", nil)
}

func HandleDocuments(w http.ResponseWriter,r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    w.Header().Set("Access-Control-Allow-Origin", "*")

    switch r.Method {
        case "GET": 
            //logic snipped
            testDoc := model.Document{"Meeting Notes", "These are some notes", time.Now(), "Bacon"}    
            sendResponse(testDoc, w,r)
            }
        case "POST":
        case "PUT":
        case "DELETE":
        default:
            //snipped
    }
}

Ideally, I'd like to send a request and get the Stamp field back as something like May 15, 2014 and not 2014-05-16T08:28:06.801064-04:00

But I'm not really sure how, I know I can add json:stamp to the Document type declaration to get the field to be encoded with the name stamp instead of Stamp, but I don't know what those types of things are called, so I'm not even sure what to google for to find out if there is some type of formatting option in that as well.

Does anyone have a link to the an example or good documentation page on the subject of those type mark ups (or whatever they're called) or on how I can tell the JSON encoder to handle time.Time fields?

Just for reference, I have looked at these pages: here and here and of course, at the official docs

答案1

得分: 121

你可以将time.Time包装为自定义类型,并使其实现Marshaler接口:

type Marshaler interface {
    MarshalJSON() ([]byte, error)
}

所以你可以这样做:

type JSONTime time.Time

func (t JSONTime) MarshalJSON() ([]byte, error) {
    // 在这里进行序列化操作
    stamp := fmt.Sprintf("\"%s\"", time.Time(t).Format("Mon Jan _2"))
    return []byte(stamp), nil
}

然后定义文档类型:

type Document struct {
    Name    string
    Content string
    Stamp   JSONTime
    Author  string
}

初始化时可以这样使用:

testDoc := model.Document{"Meeting Notes", "These are some notes", JSONTime(time.Now()), "Bacon"}

这就是大致的步骤。如果你需要反序列化,还有Unmarshaler接口可供使用。

英文:

What you can do is, wrap time.Time as your own custom type, and make it implement the Marshaler interface:

type Marshaler interface {
	MarshalJSON() ([]byte, error)
}

So what you'd do is something like:

type JSONTime time.Time

func (t JSONTime)MarshalJSON() ([]byte, error) {
    //do your serializing here
	stamp := fmt.Sprintf("\"%s\"", time.Time(t).Format("Mon Jan _2"))
	return []byte(stamp), nil
}

and make document:

type Document struct {
    Name        string
    Content     string
    Stamp       JSONTime
    Author      string
}

and have your intialization look like:

 testDoc := model.Document{"Meeting Notes", "These are some notes", JSONTime(time.Now()), "Bacon"}    

And that's about it. If you want unmarshaling, there is the Unmarshaler interface too.

答案2

得分: 73

也许对某些人来说,另一种方法可能更有趣。我想避免使用别名类型来表示时间。

type Document struct {
	Name    string
	Content string
	Stamp   time.Time
	Author  string
}

func (d *Document) MarshalJSON() ([]byte, error) {
	type Alias Document
	return json.Marshal(&struct {
		*Alias
		Stamp string `json:"stamp"`
	}{
		Alias: (*Alias)(d),
		Stamp: d.Stamp.Format("Mon Jan _2"),
	})
}

来源:http://choly.ca/post/go-json-marshalling/

英文:

Perhaps another way will be interesting for someone. I wanted to avoid using alias type for Time.

type Document struct {
	Name    string
	Content string
	Stamp   time.Time
	Author  string
}

func (d *Document) MarshalJSON() ([]byte, error) {
	type Alias Document
	return json.Marshal(&struct {
		*Alias
		Stamp string `json:"stamp"`
	}{
		Alias: (*Alias)(d),
		Stamp: d.Stamp.Format("Mon Jan _2"),
	})
}

Source: http://choly.ca/post/go-json-marshalling/

答案3

得分: 46

我不会使用以下代码:

type JSONTime time.Time

我只会在原始类型(如字符串、整数等)上使用它。对于结构体time.Time,每次使用任何time.Time方法时都需要进行类型转换。

我会使用嵌入的方式来实现:

type JSONTime struct {
    time.Time
}

func (t JSONTime)MarshalJSON() ([]byte, error) {
	// 在这里进行序列化操作
	stamp := fmt.Sprintf("\"%s\"", t.Format("Mon Jan _2"))
	return []byte(stamp), nil
}

不需要将t转换为time.Time。唯一的区别是,新实例不是通过JSONTime(time.Now())创建,而是通过JSONTime{time.Now()}创建。

英文:

I would NOT use:

type JSONTime time.Time

I would use it only for primitives (string, int, ...). In case of time.Time which is a struct, I would need to cast it every time I want to use any time.Time method.

I would do this instead (embedding):

type JSONTime struct {
    time.Time
}

func (t JSONTime)MarshalJSON() ([]byte, error) {
	//do your serializing here
	stamp := fmt.Sprintf("\"%s\"", t.Format("Mon Jan _2"))
	return []byte(stamp), nil
}

No need to cast t to time. The only difference is that new instance is NOT created by JSONTime(time.Now()) but by JSONTime{time.Now()}

答案4

得分: 9

你是指标签。但是这些标签不能解决你的格式问题。

你获取的时间的字符串表示是由Time实现的MarshalJSON返回的。

你可以通过复制Time实现中的相关部分来实现自己的MarshalJSON方法,可以通过嵌入time.Time或包装它来实现。包装的示例(点击播放):

type ShortDateFormattedTime time.Time

func (s ShortDateFormattedTime) MarshalJSON() ([]byte, error) {
    t := time.Time(s)
    if y := t.Year(); y < 0 || y >= 10000 {
        return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
    }

    return []byte(t.Format("\"Jan 02, 2006\"")), nil
}
英文:

> But I'm not really sure how, I know I can add json:stamp to the Document type declaration to get the field to be encoded with the name stamp instead of Stamp, but I don't know what those types of things are called, so I'm not even sure what to google for to find out if there is some type of formatting option in that as well.

You mean tags. But these won't help you with your formatting problem.

The string representation you get for your time is returned by MarshalJSON implemented by Time.

You can go ahead and implement your own MarshalJSON method by copying the relevant bits from the Time implementation by either embedding time.Time or wrapping it. Wrapping example (Click to play):

type ShortDateFormattedTime time.Time

func (s ShortDateFormattedTime) MarshalJSON() ([]byte, error) {
	t := time.Time(s)
	if y := t.Year(); y &lt; 0 || y &gt;= 10000 {
		return nil, errors.New(&quot;Time.MarshalJSON: year outside of range [0,9999]&quot;)
	}

	return []byte(t.Format(`&quot;Jan 02, 2006&quot;`)), nil
}

huangapple
  • 本文由 发表于 2014年5月16日 20:53:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/23695479.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定