英文:
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"
我假设这不是你的意图,而是你希望得到以下之一:
var t time.Time = time.Unix(1395800038, 0)
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:
var t time.Time = time.Unix(1395800038, 0)
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
英文:
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
答案4
得分: 0
你需要检查你另一个问题的答案这里
....
无论如何,那是一个Unix时间戳(在JavaScript中是+(new Date())
),你可以使用time.Unix
将其转换为time.Time
:
func main() {
t := 1395800038.0
fmt.Println(time.Unix(int64(t), 0))
}
//输出:2014-03-26 02:13:58 +0000 UTC
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论