无法将包含 RFC3339 的时区偏移的字符串解析为时间,并出现看似矛盾的错误

Dan*_*Dan 1 time timezone parsing go timezone-offset

我正在使用 Golang 和 time.Time 将给定字符串解析为时间对象。

使用 RFC3339,time.Parse这是我的代码示例:

t, err := time.Parse(time.RFC3339, "2020-08-08T00:22:44Z07:00")
if err != nil {
   return nil, err
}
Run Code Online (Sandbox Code Playgroud)

我收到以下错误。

当我包括时区偏移时,我得到:

ERRO[0002] parsing time "2020-08-08T00:22:44Z07:00": extra text: 07:00
Run Code Online (Sandbox Code Playgroud)

当我不包括时区偏移时,我得到:

ERRO[0002] parsing time "2020-08-08T00:15:36" as "2006-01-02T15:04:05Z07:00": cannot parse "" as "Z07:00"
Run Code Online (Sandbox Code Playgroud)

将时间解析为结构化对象时如何避免此问题?

bla*_*een 5

ZGotime.RFC3339常量中字符的存在"2006-01-02T15:04:05Z07:00"并不意味着符合模式的日期应该包含Z后跟时区偏移量。

事实上,Z后面跟有任何其他内容的日期不是有效的 RFC3339 日期。因此,你的第一个错误extra text: 07:00

代表Z“祖鲁时间”,即UTC时区。来自 RFC3339 规范:

  Z           A suffix which, when applied to a time, denotes a UTC
              offset of 00:00; often spoken "Zulu" from the ICAO
              phonetic alphabet representation of the letter "Z".
Run Code Online (Sandbox Code Playgroud)

所以Z 单独已经提供了时区信息,即UTC。

正如 @Flimzy 在评论中指出的那样,2020-08-08T00:22:44Z这将是有效的 RFC3339 日期。

    t, err := time.Parse(time.RFC3339, "2020-08-08T00:22:44Z")
    if err != nil {
        panic(err)
    }
    fmt.Println(t) // 2020-08-08 00:22:44 +0000 UTC
Run Code Online (Sandbox Code Playgroud)

现在,如果您进一步阅读 RFC3339 标准,您会看到以下定义:

time-zone       = "Z" / time-numoffset
time-numoffset  = ("+" / "-") time-hour [[":"] time-minute]
Run Code Online (Sandbox Code Playgroud)

这意味着日期的时区部分要么是aZ要么是偏移量。显然,由于Z已经表示 offset ,因此同一日期字符串中00:00不能再有一个offset 。+/-HH:mm

但这也意味着 thatZ the+/-HH:mm必须存在。因此,如果您删除它们,则会出现第二个错误:cannot parse "" as "Z07:00"

解析器尝试将字符串读取为 RFC3339,因此它需要秒(或毫秒,如果有)之后的"2020-08-08T00:15:36"a或偏移量。Z


总之,Z07:00Gotime.RFC3339模式中的 仅仅是日期字符串应该包含时区这一事实的表示。有效的 RFC3339 日期字符串必须包含Z或 偏移量。