英文:
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"),
})
}
答案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 < 0 || y >= 10000 {
return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
}
return []byte(t.Format(`"Jan 02, 2006"`)), nil
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论