无法将float32值解组为字符串。

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

Cannot unmarshal float32 value into string

问题

我有一个返回UNIX时间戳值的JSON响应,用于created字段:

"created_utc": 1395800038.0

// 我用来解组响应JSON的类型。
// 我不能使用字符串,因为Golang会报错,说JSON是一个浮点数。
type Submission struct {
CreatedUtc float32 json:"created_utc"
}

我想将其转换为实际的Time对象:

const longForm = "Jan 2, 2006 at 3:04pm (MST)"
created_at, _ := time.Parse(longForm, string(created_utc))

./main.go:57: 无法将created_utc (类型为float32) 转换为字符串类型


所以我有点困在这里。要么我可以强制解组代码将时间戳转换为字符串,要么我可以在time.Parse代码中将浮点值转换为字符串 - 但是我似乎无法做到这两者,否则Golang会报错。

英文:

I have a JSON response that returns a UNIX timestamp value for the created field:

"created_utc": 1395800038.0

---

// The type I use to marshal the response JSON.
// I can't use string because Golang complains the JSON is a float.
type Submission struct {
	CreatedUtc          float32         `json:"created_utc"`
}

I want to convert this to an actual Time object:

const longForm = "Jan 2, 2006 at 3:04pm (MST)"
created_at, _ := time.Parse(longForm, string(created_utc))

>./main.go:57: cannot convert created_utc (type float32) to type string


So I'm sort of stuck here. Either I can force the marshal code to convert the timestamp to a string, or I can convert the float value to a string on the time.Parse code - but I can't seem to do either without Golang complaining.

答案1

得分: 4

你的代码有几个问题:

使用float32存储Unix时间戳

正如Nick Craig-Wood已经指出的,float32无法存储Unix时间戳而不丢失精度。虽然JSON标准不限制数字的精度,但JavaScript将它们限制为IEEE 754 64位浮点数值。

话虽如此,最好的做法是将JSON数字存储在float64变量中,以避免丢失精度,除非你确定该数字适合int(没有小数)或float32,或其他类型。

将float64转换为字符串以获取时间?

将float转换为字符串的示例:

> 1395800038.0 => "1395800038.0"

我假设这不是你的意图,而是你希望得到以下之一:

  1. var t time.Time = time.Unix(1395800038, 0)
  2. var s string = "Mar 26, 2014 at 2:13am (UTC)" // 或其他任何格式

即使你的目标是得到字符串(2),你仍然需要创建time.Time变量(1)。因此,这将分为两个步骤。

解决方案:

package main

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

var data = []byte(`{"created_utc": 1395800038.0}`)

type Submission struct {
	CreatedUtc float64 `json:"created_utc"`
}

func main() {
	var sub Submission
	err := json.Unmarshal(data, &sub)
	if err != nil {
		panic(err)
	}

	// 第一步,将float64转换为time.Time(同时进行快速的int64转换)
	dt := time.Unix(int64(sub.CreatedUtc), 0)

	// 第二步,将时间戳转换为所需的字符串表示形式
	fmt.Println(dt.Format("2006-01-02 15:04:05"))
}

结果:

2014-03-26 02:13:58

Playground: http://play.golang.org/p/jNwzwc4dLg

英文:

There are a few things wrong with your code:

Using float32 for a Unix timestamp

As Nick Craig-Wood already pointed out, a float32 cannot store a Unix timestamp without loss of precision. And while the JSON standard doesn't restrict the precision of a number, Javascript restricts them to IEEE 754 64-bit floating point values.

That being said, it is a good practice to store JSON numbers in float64 variables to avoid loosing precision, unless you are certain the number fits well in an int (no decimals) or float32, or whatever.

Converting float64 to string to get Time?

Converting float to string sounds like:

> 1395800038.0 => "1395800038.0"

I will assume that is not your intent, but rather that wish to get one of the following:

  1. var t time.Time = time.Unix(1395800038, 0)
  2. var s string = "Mar 26, 2014 at 2:13am (UTC)" // Or any other format

And even if your aim is to get to the string (2), you still would need to create the time.Time variable (1). So it will happen in two steps.

Solution:

package main

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

var data = []byte(`{"created_utc": 1395800038.0}`)

type Submission struct {
	CreatedUtc float64 `json:"created_utc"`
}

func main() {
	var sub Submission
	err := json.Unmarshal(data, &sub)
	if err != nil {
		panic(err)
	}

	// First step, convert float64 to a time.Time (after a quick conversion to int64 as well)
	dt := time.Unix(int64(sub.CreatedUtc), 0)

	// Second step, convert the timestamp to a string representation of your choice
	fmt.Println(dt.Format("2006-01-02 15:04:05"))
}

Result:

2014-03-26 02:13:58

Playground: http://play.golang.org/p/jNwzwc4dLg

答案2

得分: 2

你应该使用int64来存储UNIX时间(float没有意义)。

然后使用以下代码将其转换为time.Time实例:

var x int64 = 1398621956

dt := time.Unix(x, 0) // 将nsec设置为0
created_at := dt.Format("Jan 2, 2006 at 3:04pm (MST)")

fmt.Println(created_at)

如果你真的必须使用float,请使用float64(这将避免解析问题),然后使用以下代码将其转换为int64

var y float64 = 1398621956.0
x := int64(y)
英文:

You should use int64 to store the UNIX time (float doesn't make sense).

Then use this to convert it to a time.Time instance:

var x int64 = 1398621956
	
dt := time.Unix(x, 0) // setting nsec to 0
created_at := dt.Format("Jan 2, 2006 at 3:04pm (MST)")

fmt.Println(created_at)

If you really have to use float use float64 (this will prevent the parsing issue) and use this to convert to int64:

var y float64 = 1398621956.0
x := int64(y)

答案3

得分: 2

不要在float32中存储Unix时间戳,因为它不适合!

一个float32只有24位的尾数,而当前的Unix时间需要31位。

所以,如果你将Unix时间存储在float32中,你将会失去精度,例如:

func main() {
    t := 1395800038.0
    v := float32(t)
    dv := float64(v) - t
    fmt.Printf("v = %f, difference is %f\n", v, dv)
}

这将打印出:

v = 1395800064.000000, difference is 26.000000

Playground

英文:

Don't store a unix timestamp in a float32 it doesn't fit!

A float32 has only 24 bits of mantissa - whereas a current unix time needs 31 bits.

So if you do store a unix time in a float32 you'll get reduced precision, eg

func main() {
	t := 1395800038.0
	v := float32(t)
	dv := float64(v) - t
	fmt.Printf("v = %f, difference is %f\n", v, dv)
}

Which prints

v = 1395800064.000000, difference is 26.000000

(Playground)

答案4

得分: 0

你需要检查你另一个问题的答案这里....

无论如何,那是一个Unix时间戳(在JavaScript中是+(new Date())),你可以使用time.Unix将其转换为time.Time

Play链接

func main() {
    t := 1395800038.0
    fmt.Println(time.Unix(int64(t), 0))
}
//输出:2014-03-26 02:13:58 +0000 UTC
英文:

You need to check your other question's answer here....

Anyway, that's a unix timestamp (in javascript +(new Date())), you can use time.Unix to convert it to time.Time :

Play link

func main() {
	t := 1395800038.0
	fmt.Println(time.Unix(int64(t), 0))
}
//output : 2014-03-26 02:13:58 +0000 UTC

huangapple
  • 本文由 发表于 2014年4月28日 01:54:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/23326908.html
匿名

发表评论

匿名网友

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

确定