【问题标题】:How to represent the RFC-3339 `-00:00` offset in Go?如何在 Go 中表示 RFC-3339 `-00:00` 偏移量?
【发布时间】:2018-03-28 16:01:53
【问题描述】:

RFC-3339 第 4.3 节 (https://www.rfc-editor.org/rfc/rfc3339#section-4.3) 将-00:00 偏移量定义如下,与Z+00:00 不同。

4.3. Unknown Local Offset Convention

   If the time in UTC is known, but the offset to local time is unknown,
   this can be represented with an offset of "-00:00".  This differs
   semantically from an offset of "Z" or "+00:00", which imply that UTC
   is the preferred reference point for the specified time.  RFC2822
   [IMAIL-UPDATE] describes a similar convention for email.

但是,我不确定如何在 Go 中表示这一点。当我用-00:00 解析时间并对其进行格式化时,我得到一个Z 偏移量。例如:

  • 输入:2018-01-01T00:00:00-00:00
  • 输出:2018-01-01T00:00:00Z

这是一些示例代码 (https://play.golang.org/p/CVmNnhaSiiT):

package main

import (
    "fmt"
    "time"
)

func main() {
    t := "2018-01-01T00:00:00-00:00"
    fmt.Println("Input  " + t)
    p, err := time.Parse(time.RFC3339, t)
    if err != nil {
        fmt.Println(err)
    } else {
        t2 := p.Format(time.RFC3339)

        fmt.Println("Output " + t2)
    }
}

【问题讨论】:

  • 我不认为 Go 的 time 包有未知偏移量的概念;它没有什么特别的用处。如果偏移量确实未知,则时间本身有些无用,因为任何解释都可能不准确 +/- 12 小时 - 足以使偶数日期可能偏离 +/- 1 天。
  • 当使用-00:00 时,时间是准确的,因为 RFC 说“UTC 时间是已知的”。只是偏移量是未知的,例如,如果我们有一个时间2018-01-01T12:00:00-00:00,我们知道确切的时间,但不知道偏移量,例如时间是2018-01-01T11:00:00-01:00还是2018-01-01T13:00:00+01:00
  • 在这种情况下,它的语言环境是 UTC。除了及时识别实例之外,提供任何信息不是时间的义务。说“在 UTC 中午,但我不知道它实际发生在哪个地区”的时间是指与 time.Time 无关的“它”。

标签: go time


【解决方案1】:

Package time

import "time"

RFC3339、RFC822、RFC822Z、RFC1123 和 RFC1123Z 适用于 格式化;当与 time.Parse 一起使用时,它们并不总是接受 RFC 允许的格式。


Go 不接受 RFC 允许的所有时间格式。

Go time.Time 类型使用整数,与浮点不同,整数没有正负零的概念。解析-00:00+00:00的偏移量结果是一样的。

例如,

package main

import (
    "fmt"
    "time"
)

func main() {
    var err error
    var minus, plus time.Time
    t := "2018-01-01T00:00:00-00:00"
    minus, err = time.Parse(time.RFC3339, t)
    if err != nil {
        fmt.Println(err)
    }
    t = "2018-01-01T00:00:00+00:00"
    plus, err = time.Parse(time.RFC3339, t)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(minus, plus, minus.Equal(plus), minus == plus)
}

游乐场:https://play.golang.org/p/Urf8VlKYoMH

输出:

2018-01-01 00:00:00 +0000 UTC 2018-01-01 00:00:00 +0000 UTC true true

【讨论】:

  • 关于“他们不接受 RFC 允许的所有时间格式”,-00:00 偏移量被接受,因为它解析没有错误。但是,似乎转换可能是有损的。
  • @Grokify: time.Parse 不接受正零和负零偏移格式之间的区别。
  • @Grokify:我建议你看看实际的code。解析负偏移量时,唯一要做的就是反转计算的正偏移量。所以正如这里所说,一个整数 -0 等于 +0 并且简单地反转它,关于它的信息就会丢失。
  • 我同意。 “有关它的信息会丢失”是我说转换是有损的原因。
【解决方案2】:

PeterSO 的回答是完美的恕我直言。如果您需要根据偏移量未知的信息采取不同的行动,那么这可能会对您有所帮助。

您可以构建自己的时间数据类型:

type MyTime struct {
    // based on time.Time so we can do all normal time.Time stuff
    time.Time

    offsetUnknown bool
}

func ParseRFC3339(s string) (MyTime, error) {
    time, err := time.Parse(time.RFC3339, s)
    if err != nil {
        return MyTime{}, err
    }

    return MyTime{
        Time: time,
        // maybe this condition needs improvement in case of false positives
        offsetUnknown: strings.Contains(s, "-00:00"),
    }, nil
}

您需要基于offsetUnknown 表现不同的任何函数,然后您可以覆盖MyTime 结构。这里有一个例子:

func (s MyTime) Format(layout string) string {
    out := s.Time.Format(layout)
    // again this is probably not the best solution
    if layout == time.RFC3339 && s.offsetUnknown {
        out = strings.Replace(out, "+00:00", "-00:00", -1)
    }
    return out
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多