英文:
Golang JSON time default layout varies by platform?
问题
我遇到了一个奇怪的问题,即time.Time
的JSON编码字符串在我的开发环境(OSX)和生产环境(Ubuntu 14.04 x64)之间有所不同。
type Thang struct {
CreatedAt time.Time `json:"created_at"`
}
在OSX上:
{
// RFC3339格式
"created_at": "2015-04-24T22:39:59Z",
}
在Ubuntu 14.04 x64上:
{
// RFC3339Nano格式
"created_at": "2015-05-21T15:00:46.546000003Z",
}
我已经搜索了很久,但无法解决这个问题。以下是一些更多的信息:
- 这是一个简单的Web服务应用程序
- 在我的OSX机器上运行
go 1.4.1
- 我在OSX机器上进行交叉编译以进行部署,命令如下:
GOOS=linux GOARCH=amd64 go build
希望能得到任何见解!
英文:
I'm having a strange issue where the JSON encoded string of a time.Time
is varying between my development environment (OSX) and production environment (Ubuntu 14.04 x64).
type Thang struct {
CreatedAt time.Time `json:"created_at"`
}
OSX:
{
// RFC3339 layout
created_at: "2015-04-24T22:39:59Z",
}
Ubuntu 14.04 x64:
{
// RFC3339Nano layout
created_at: "2015-05-21T15:00:46.546000003Z",
}
I've googled around forever. Can't figure this one out. Here's some more info:
- It's a straight forward web services app
- Running
go 1.4.1
on my OSX machine - I cross compile the app on my OSX machine for deployment like this:
GOOS=linux GOARCH=amd64 go build
Would appreciate any insight!
答案1
得分: 2
time.Time
的MarshalJSON
方法的源代码如下:
// MarshalJSON implements the json.Marshaler interface.
// The time is a quoted string in RFC 3339 format, with sub-second precision added if present.
func (t Time) MarshalJSON() ([]byte, error) {
if y := t.Year(); y < 0 || y >= 10000 {
// RFC 3339 is clear that years are 4 digits exactly.
// See golang.org/issue/4556#c15 for more discussion.
return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
}
return []byte(t.Format(`"` + RFC3339Nano + `"`)), nil
}
在所有平台上都是相同的。
注意:
[…] with sub-second precision added if present.
而RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
。
其中的"9"表示使用最多这么多位数,但会去除尾部的零。
所以你的两个示例都可以匹配这个格式。
(而且在解析时间时,Go始终接受并解析小数秒,无论格式如何)。
RFC3339的第5.6节指定小数秒是可选的,可能包含也可能不包含(只要小数点存在,后面必须至少有一位数字)。
有没有什么原因导致你在某个系统上使用的时间只有秒的精度,或者类似的情况?(比如,这是来自某个文件系统或其他子系统,在某个操作系统上只存储秒的信息?)
英文:
The source for time.Time
's MarshalJSON
is:
// MarshalJSON implements the json.Marshaler interface.
// The time is a quoted string in RFC 3339 format, with sub-second precision added if present.
func (t Time) MarshalJSON() ([]byte, error) {
if y := t.Year(); y < 0 || y >= 10000 {
// RFC 3339 is clear that years are 4 digits exactly.
// See golang.org/issue/4556#c15 for more discussion.
return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
}
return []byte(t.Format(`"` + RFC3339Nano + `"`)), nil
}
[time.MarshalJSON
source on GitHub]
and is the same on all platforms.
Note:
> […] with sub-second precision added if present.
And that RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
.
The "9"'s mean use up-to that many digits but remove trailing zeros.
So it looks like both your examples can match this format.
(And when parsing times Go always accepts and parses fractional seconds no matter what the format says).
Section 5.6 of RFC3339 specifies that the fractional seconds are optional and may or may not be included (only saying that if the decimal point is present it must be followed by at least one digit).
For some reason does the time you're using on one system only have second accuracy or some such? (e.g. does this come from some filesystem or other sub-system that only stores seconds on one of the OSes?).
答案2
得分: 1
RFC3339并未对时间的精度做出具体规定。似乎Ubuntu坚持在时间上添加了另外九位小数的精度,这在RFC3339中是可以接受的。
在iOS / MacOS X上,相同的日期格式解析器无法同时解析带有和不带有小数点的秒数,因此我使用了两种格式:
"yyyy-MM-dd'T'HH:mm:ssX5"
"yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSX5"
并尝试两种格式。(实际上,我使用了六个S字符,因为我认为没有理智的人会使用超过六位小数,但这是错误的)。
我认为iOS / MacOS X中的日期格式是由Unicode标准规范化的,所以其他解析器可能也适用。出于效率考虑,我会记住上次成功解析的解析器,并首先尝试该解析器 - 如果你得到了一个带有纳秒的日期,那么下一个日期很可能也会有纳秒。
英文:
RFC3339 doesn't say anything about the precision of the time. Seems that Ubuntu insists on adding another nine decimal digits of precision, which is fine according to RFC3339.
On iOS / MacOS X the same date format parser cannot parse seconds with and without a decimal point, so I use two formats
"yyyy'-'MM'-'dd'T'HH':'mm':'ssX5"
"yyyy'-'MM'-'dd'T'HH':'mm':'ss.SSSSSSSSSX5"
and try both. (Actually I had six S characters because I thought nobody sane would use more than six decimals. That was wrong).
I think the date formats in iOS / MacOS X are standardised by the Unicode standard, so that might apply to other parsers as well. For efficiency reasons, I would remember which parser worked the last time and try that one first - if you got one date with nanoseconds, then the next date is likely to have nanoseconds as well.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论