Parse .Net JSON date with Go

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

Parse .Net JSON date with Go

问题

如何使用Go解析这个.NET JSON日期?值返回未分配。它似乎只解析到日期字段。

package main

import (
	"encoding/json"
	"fmt"
	"time"
)

type MyStruct struct {
	FirstField string
	SomeTime   time.Time
	LastField  string
}

type MyStructSlice struct {
	MyStructs []MyStruct
}

func main() {
	var s MyStructSlice
	str := `{"MyStructs":[{"FirstField":"123", "SomeTime":"\/Date(1432187580000-0500)\/", "LastField":"456"}]}`
	json.Unmarshal([]byte(str), &s)
	fmt.Println(s)
}

Go Playground

英文:

How can I parse this .Net JSON date with Go?
The value comes back unassigned.
It appears to parse up to the date field.

package main

import (
	"encoding/json"
	"fmt"
	"time"
)

type MyStruct struct {
	FirstField string
	SomeTime time.Time
	LastField string
}

type MyStructSlice struct {
	MyStructs []MyStruct
}

func main() {
	var s MyStructSlice 
	str := `{"MyStructs":[{"FirstField":"123", "SomeTime":"\/Date(1432187580000-0500)\/", "LastField":"456"}]}`
	json.Unmarshal([]byte(str), &s)
	fmt.Println(s)
}

Go Playground

答案1

得分: 1

我将提供一些建议。不过你需要自己编写代码 Parse .Net JSON date with Go

首先,能否更改生成此JSON的.NET应用程序,以生成更易解析的内容?如果将日期时间输出为RFC3339格式(例如1990-12-31T15:59:12-08:00),那么Go语言将自动将其转换为time.Time实例,感谢http://golang.org/pkg/time/#Time.UnmarshalJSON。

如果无法更改客户端,则需要自己解析此日期:

  1. 从字符串中提取时间部分(1432187580000)。这看起来像是自UNIX纪元以来的毫秒数(ms)。你可以使用time.Unix(sec, nsec)将其转换为time.Time实例。

  2. (可选)在上一步中创建的时间已经准确表示了一个时间点。但是,如果你想要添加原始时区(例如打印它),则需要:

  • 从字符串中解析偏移部分(-0500)
  • 创建time.FixedZone
  • 在第一步中创建的time.Time实例上调用http://golang.org/pkg/time/#Time.In

示例:http://play.golang.org/p/Pkahyg2vZa

英文:

I am going to provide a few suggestions. You will have to write the code yourself though Parse .Net JSON date with Go

First of all is it possible to change .NET application that produced this JSON to generate something more parsable? If you make it output datetime in RFC3339 format (something like 1990-12-31T15:59:12-08:00) then go will automatically converts it to time.Time instance thanks to http://golang.org/pkg/time/#Time.UnmarshalJSON

If you cannot change the client then you will have to parse this date yourself:

  1. extract time part (1432187580000) from the string. this looks like number of milliseconds (ms) since UNIX epoch. You can convert it to time.Time instance using time.Unix(sec, nsec).

  2. (optional). The time that was created in the last step already accurately represent a point in time. However if you want to add the original timezone to it (e.g. to print it) you will need to:

Example: http://play.golang.org/p/Pkahyg2vZa

答案2

得分: 0

值未分配的原因有很多。首先,你的MyStruct看起来不对。你的JSON有一个名为data的键作为父键,其中包含一个对象数组。

但是你的结构体却不像这样。它至少要有一个Date字段。所以让你的结构体看起来像你接收到的JSON。

另一件事是,你的time.Time无法解析这个字符串:Date(1432187580000-0500),它不是一个正常的日期。

附注:现在你已经将你的结构体更新为正常的方式,你必须找到一种方法将你奇怪的字符串解析为日期。如果你对你的.NET应用程序有控制权,我建议将JSON更改为一个正常的时间戳或其他易于解析的格式。

如果没有,那么你必须将SomeTime time.Time更改为SomeTime string,然后将字符串解析为正常的时间戳,然后将该时间戳解析为日期。

英文:

The value comes back unassigned for many reasons. First of all your MyStruct does not look right. Your JSON has data key as the parent key, which consists an array of objects.

But your struct for some reason does not even resembles this. It has to have Date as a field at least. So make your struct look like the json you are receiving.

Another thing is that your time.Time will not be able to parse this string: Date(1432187580000-0500) in a normal date.

P.S. now that you have updated your struct to normal way, you have to find a way to parse your strange sting to a date. If you have power over your .net application, I would rather recommend changing json to a normal timestamp or something that can be easily parsable.

If not, then you have to change SomeTime time.Time to SomeTime string and then parse string to a normal timestamp and then parse this timestamp to a date.

答案3

得分: 0

首先,你的模型是错误的,它没有正确地建模你的JSON数据结构。应该是这样的:

type Data struct {
    Data []MyStruct `json:"data"`
}

type MyStruct struct {
    SomeTime string
}

使用这个结构可以正常工作,在Go Playground上试一试。

问题是时间仍然是一个字符串。

如果你想要SomeTimetime.Time类型,你需要自己解析它,可以通过实现json.Unmarshaler来实现:

type Data struct {
    Data []MyStruct `json:"data"`
}

type MyStruct struct {
    SomeTime time.Time
}

func (m *MyStruct) UnmarshalJSON(data []byte) error {
    // 首先将其解析为字符串:
    ms := struct{ SomeTime string }{}
    if err := json.Unmarshal(data, &ms); err != nil {
        return err
    }

    s := ms.SomeTime

    // s 的格式为:"/Date(1432187580000-0500)/"
    // 提取毫秒和时区偏移小时数
    i1 := strings.Index(s, "(")
    i3 := strings.Index(s, ")")
    i2 := strings.Index(s, "-")
    if i2 < 0 {
        i2 = strings.Index(s, "+")
    }
    if i1 < 0 || i2 < 0 || i3 < 0 {
        return errors.New("无效的格式")
    }

    millis, err := strconv.ParseInt(s[i1+1:i2], 10, 64)
    if err != nil {
        return err
    }
    m.SomeTime = time.Unix(0, millis*1000000)

    // 应用时区:
    zoneHours, err := strconv.ParseInt(s[i2:i3], 10, 64)
    if err != nil {
        return err
    }
    zone := time.FixedZone("something", int(zoneHours)*3600)
    m.SomeTime = m.SomeTime.In(zone)
    return nil
}

Go Playground上试一试。

英文:

First you model is wrong, it doesn't model the data structure in your JSON. It should be:

type Data struct {
Data []MyStruct `json:&quot;data`
}
type MyStruct struct {
SomeTime string
}

It works with this, try it on the Go Playground.

Problem is that we still have the time as string.

Now if you want SomeTime to be time.Time, you need to parse it yourself, you can do it by implementing json.Unmarshaler:

type Data struct {
Data []MyStruct `json:&quot;data`
}
type MyStruct struct {
SomeTime time.Time
}
func (m *MyStruct) UnmarshalJSON(data []byte) error {
// First unmashal it into a string:
ms := struct{ SomeTime string }{}
if err := json.Unmarshal(data, &amp;ms); err != nil {
return err
}
s := ms.SomeTime
// s is of format: &quot;/Date(1432187580000-0500)/&quot;
// extract millis and time zone offset hours
i1 := strings.Index(s, &quot;(&quot;)
i3 := strings.Index(s, &quot;)&quot;)
i2 := strings.Index(s, &quot;-&quot;)
if i2 &lt; 0 {
i2 = strings.Index(s, &quot;+&quot;)
}
if i1 &lt; 0 || i2 &lt; 0 || i3 &lt; 0 {
return errors.New(&quot;Invalid format&quot;)
}
millis, err := strconv.ParseInt(s[i1+1:i2], 10, 64)
if err != nil {
return err
}
m.SomeTime = time.Unix(0, millis*1000000)
// Apply timezone:
zoneHours, err := strconv.ParseInt(s[i2:i3], 10, 64)
if err != nil {
return err
}
zone := time.FixedZone(&quot;something&quot;, int(zoneHours)*3600)
m.SomeTime = m.SomeTime.In(zone)
return nil
}

Try it on the Go Playground.

huangapple
  • 本文由 发表于 2015年5月21日 14:25:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/30366045.html
匿名

发表评论

匿名网友

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

确定