解析时间时,Mac OSX上的Golang空位置

解析时间时,Mac OSX上的Golang空位置

问题描述:

(Edit/update): Thanks to @djd for pointing out that we can skip all the JSON/struct decoding business; the key issue is with time.Parse.

The same issue comes up here where the Location is "empty" rather than UTC (I would've expected UTC based on the docs: https://golang.org/pkg/time/#Parse

"In the absence of a time zone indicator, Parse returns a time in UTC."

Here's the example code: https://play.golang.org/p/pb3eMbjSmv

package main

import (
    "fmt"
    "time"
)

func main() {
    // Ignoring the err just for this example's sake!
    parsed, _ := time.Parse(time.RFC3339, "2017-08-15T22:30:00+00:00")
    fmt.Printf("String(): %v
", parsed.String())
    fmt.Printf("Location(): %v
", parsed.Location())
}

which outputs

String(): 2017-08-15 22:30:00 +0000 +0000
Location():

So while the offset of the time.Time's Location appears to be correct, its timezone name is just an empty string. Running in on other machines (and The Go Playground) give the expected "UTC" location.

[Original post]:

When decoding a timestamp field from JSON into a struct on my local OS X machine, the Location of the time.Time field is "empty" rather than UTC. This is problematic for me running unit tests locally (vs. on a CI server where the Location is being set correctly to be UTC).

When I run that on my machine, I see

go run main.go TimeField.String(): 2017-08-15 22:30:00 +0000 +0000 TimeField.Location():

So while the offset of the time.Time's Location appears to be correct, its timezone name is just an empty string. This is using Go 1.5:

go version go version go1.5 darwin/amd64

(编辑/更新):感谢@djd指出我们可以跳过所有JSON / struct解码业务 ; 关键问题在于 time.Parse code>。 p>

这里出现了同样的问题,其中 Location code>是“空”而不是UTC (我期望基于以下文档的UTC: https://golang.org/pkg/time/ #Parse p>

“在没有时区指示符的情况下,Parse以UTC返回时间。” p>

下面是示例代码 : https://play.golang.org/p/pb3eMbjSmv p> \ n

 包main 
 
import(
“ fmt” 
“ time” 
)
 
func main(){
 //忽略 仅出于本示例的目的而犯错!
已解析,_:= time.Parse(time.RFC3339,“ 2017-08-15T22:30:00 + 00:00”)
 fmt.Printf(“ String():  %v 
“,已解析。String())
 fmt.Printf(” Location():%v 
“,已解析。Location())
} 
  code>  pre> 
  
 

输出 p>

  String():2017-08-15 22:30:00 +0000 +0000 
Location():
  code>   PRE> 
 
 

因此,虽然 time.Time code>的 Location code>的偏移量看起来正确,但其时区名称只是一个空字符串。 在其他计算机(和Go Playground)上运行时,将提供预期的“ UTC”位置。 p>

[原始帖子]: p>

解码时间戳时 从JSON字段转换为本地OS X计算机上的 struct code>字段,time.Time code>字段的 Location code>字段为“空”而不是UTC。 这对于我在本地运行单元测试(相对于在CI服务器上将 Location code>正确设置为UTC的CI服务器)来说是个问题。 p>

当我运行该单元测试时 在我的机器上,我看到 p>

去运行main.go TimeField.String():2017-08-15 22:30:00 +0000 +0000 TimeField.Location (): code> p>

因此,虽然 time.Time time>的 Location code>的偏移量似乎正确 ,其时区名称只是一个空字符串。 这是使用Go 1.5: p>

go版本 go版本go1.5 darwin / amd64 code> p> div>

I find same behavior using my current setup on Mac and I suspect it will be same behavior on Linux (not sure through)

$ go version
go version devel +31ad583 Wed Aug 10 19:44:08 2016 +0000 darwin/amd64

To make it more deterministic, I suggest using a custom json Unmarshal like so:

package main

import (
  "encoding/json"
  "fmt"
  "strings"
  "time"
)

type Time struct {
   *time.Time
}

func (t *Time) UnmarshalJSON(b []byte) error {
  const format = "\"2006-01-02T15:04:05+00:00\""
  t_, err := time.Parse(format, string(b))
  if err != nil {
      return err
  }
  *t = Time{&t_}
  return nil
}

type Example struct {
  TimeField *Time `json:"time_field"`
}

func main() {
  inString := "{\"time_field\": \"2017-08-15T22:30:00+00:00\"}"
  var ex Example
  decoder := json.NewDecoder(strings.NewReader(inString))
  decoder.Decode(&ex)
  fmt.Printf("TimeField.String(): %v
", ex.TimeField.String())
  fmt.Printf("TimeField.Location(): %v
", ex.TimeField.Location())
}

Yes, You are right. On The Go Playground the Local is set to UTC inside that sandbox:
Try this working sample code on The Go Playground:

package main

import (
    "fmt"
    "runtime"
    "time"
)

func main() {
    fmt.Println(runtime.Version(), runtime.GOARCH, runtime.GOOS) //go1.7 amd64p32 nacl

    parsed, err := time.Parse(time.RFC3339, "2017-08-15T22:30:00+00:00")
    if err != nil {
        panic(err)
    }
    fmt.Printf("String(): %v
", parsed.String())
    fmt.Printf("Location(): %v
", parsed.Location())
}

output on The Go Playground:

go1.7 amd64p32 nacl
String(): 2017-08-15 22:30:00 +0000 UTC
Location(): UTC 

And try it on your local system, output Location() is empty.


You may use utc := parsed.UTC() with the location set to UTC, like this working sample code The Go Playground:

package main

import (
    "fmt"
    "runtime"
    "time"
)

func main() {
    fmt.Println(runtime.Version(), runtime.GOARCH, runtime.GOOS) //go1.7 amd64p32 nacl

    parsed, err := time.Parse(time.RFC3339, "2017-08-15T22:30:00+00:00")
    if err != nil {
        panic(err)
    }
    fmt.Printf("String(): %v
", parsed.String())
    fmt.Printf("Location(): %v
", parsed.Location())
    utc := parsed.UTC()
    fmt.Printf("String(): %v
", utc.String())
    fmt.Printf("Location(): %v
", utc.Location())
}

Also You may use time.ParseInLocation(time.RFC3339, "2017-08-15T22:30:00+00:00", time.UTC), like this working sample code:

package main

import (
    "fmt"
    "runtime"
    "time"
)

func main() {
    fmt.Println(runtime.Version(), runtime.GOARCH, runtime.GOOS) //go1.7 amd64p32 nacl

    parsed, err := time.ParseInLocation(time.RFC3339, "2017-08-15T22:30:00+00:00", time.UTC)
    if err != nil {
        panic(err)
    }
    fmt.Printf("String(): %v
", parsed.String())
    fmt.Printf("Location(): %v
", parsed.Location())
}

So the Location() will be UTC.