我正在尝试使用time.Parse
解析“Tue Jun 11 2019 13:26:45 GMT + 0000”和“Mon Jan 02 2006 15:04:05 MST-0700”作为布局字符串,但我收到此错误parsing time "Tue Jun 11 2019 13:26:45 GMT+0000" as "Mon Jan 02 2006 15:04:05 MST-0700": cannot parse "" as "-0700"
。
我一直在使用上述布局字符串作为其他偏移量,并且效果很好。但是,我认为“+0000”不是有效的偏移量吗?任何的意见都将会有帮助。
编辑:使用“Mon Jan 02 2006 15:04:05 GMT-0700”作为布局工作,我得到的输出为2019-06-11 13:26:45 +0000 +0000
。
最佳答案
编辑2:根据reply in github issues,事实证明,在布局字符串“MST-0700”中实际上是两个时区值"MST"
和数字时区值"-0700"
,它们优先于前者。并且"GMT+08"
或"GMT+00"
整体上被视为时区值,并且与“MST”匹配。因此它将是"GMT+08+0800"
的"MST-0700"
。
我很少涉及与时区相关的问题,但我个人认为这种行为令人困惑。
原始答案:
这是一个混淆Go时间库行为的错误。虽然我不确定GMT时间格式的预期行为(因为我很少在时间格式字符串中看到GMT+0800
之类的东西),但是使GMT+0800
有效但GMT+0000
的代码逻辑没有意义。
我已经在github上提交了一个问题:https://github.com/golang/go/issues/40472
简而言之,Go的时间库通过同时使用布局字符串和值字符串来解析格式。当前,在解析“GMT”时区时,如果以下值字符串(例如,“+ 0800”或“+0000”)已签名且范围从-23
到+23
,它将消耗更多的值字符串。因此,不仅"GMT+0000"
失败,而且"GMT+0030"
和"GMT+08"
(与“MST-07”匹配时)也失败。
详细信息如下:解析时区时,它会检查布局字符串并找到“MST”,因此它将尝试解析值字符串中的时区值,该值字符串当时只有“GMT + 0X00”(其中X为'0'或'8')-其他(已正确使用)。 Source
case stdTZ:
// Does it look like a time zone?
if len(value) >= 3 && value[0:3] == "UTC" {
z = UTC
value = value[3:]
break
}
n, ok := parseTimeZone(value)
if !ok {
err = errBad
break
}
zoneName, value = value[:n], value[n:]
在这里一切都很好。 parseTimeZone函数对GMT格式有特殊情况,原因对我来说并不明显,但是here is the code:// Special case 2: GMT may have an hour offset; treat it specially.
if value[:3] == "GMT" {
length = parseGMT(value)
return length, true
}
然后parseGMT
代码就像this:// parseGMT parses a GMT time zone. The input string is known to start "GMT".
// The function checks whether that is followed by a sign and a number in the
// range -23 through +23 excluding zero.
func parseGMT(value string) int {
value = value[3:]
if len(value) == 0 {
return 3
}
return 3 + parseSignedOffset(value)
}
从注释中,我们已经可以感觉到问题:“+ 0800”不是从-23
到+23
的范围内的数字(不包括前导零)(而“+0000”)。显然,此函数试图(根据返回值)指示要消耗3个以上的字节,这比“GMT”要多。我们可以在code of parseSignedOffset
中确认。// parseSignedOffset parses a signed timezone offset (e.g. "+03" or "-04").
// The function checks for a signed number in the range -23 through +23 excluding zero.
// Returns length of the found offset string or 0 otherwise
func parseSignedOffset(value string) int {
sign := value[0]
if sign != '-' && sign != '+' {
return 0
}
x, rem, err := leadingInt(value[1:])
// fail if nothing consumed by leadingInt
if err != nil || value[1:] == rem {
return 0
}
if sign == '-' {
x = -x
}
if x < -23 || 23 < x {
return 0
}
return len(value) - len(rem)
}
在这里,leadingInt
是一个无趣的函数,它将string
的前缀转换为int64
以及字符串的其余部分。因此,
parseSignedOffset
做了文档中所宣传的:它解析值字符串,并查看它是否处于-23
到+23
的范围内,但实际值是:+0800
视为800
,大于+23
,因此返回0
。结果,parseGMT
(和parseTimeZone
)返回3
,因此这次Parse
函数仅消耗3个字节,并保留"+0800"
与"-0700"
匹配,因此可以正确解析。+0000
视为范围内的有效值0
,因此返回5,表示“+0000”是时区的一部分,因此parseGMT
(和parseTimeZone
)返回8,使得Parse
函数消耗了整个字符串,保留""
与"-0700"
匹配,从而导致错误。编辑:
在格式字符串中使用GMT并获取“正确的”值是因为格式字符串中的“GMT”不被视为时区,而是格式的一部分(就像字符串中的空格一样)和“GMT”时区与默认时区(“UTC”)相同。
您可以
time.Parse("Mon Jan 02 2006 15:04:05 XYZ-0700", "Tue Jun 11 2019 13:26:45 XYZ+0800")
而不会出现错误。
关于go - 解析时区为 “GMT+0000”的时间字符串时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63150212/