dpiuqwwyu187975836 2018-12-15 03:47
浏览 26
已采纳

编组/解组后,当地时间损失52秒

I parse a time in Local, marshal it to JSON, un-marshal it and the times no longer match.

timeA, _ := time.ParseInLocation("15:04", "8:00", time.Local)

jBytes, _ := json.Marshal(timeA)

var timeB time.Time

json.Unmarshal(jBytes, &timeB)

fmt.Printf("Time A: %+v, Time B: %+v
", timeA, timeB)
fmt.Printf("Time A: %+v, Time B: %+v
", timeA.Local(), timeB.Local())
fmt.Printf("Diff: %s
", timeA.Sub(timeB))
fmt.Printf("Marshaled: %s", string(jBytes))

Time A: 0000-01-01 08:00:00 -0733 LMT, Time B: 0000-01-01 08:00:00 -0733 -0733

Time A: 0000-01-01 08:00:00 -0733 LMT, Time B: 0000-01-01 07:59:08 -0733 LMT

Diff: 52s

Marshaled: "0000-01-01T08:00:00-07:33"

This is running on linux with Edmonton/Mountain as my local time so I guess it's not recognizing the location and showing offset twice -733 -733. When I call local, the parsed one consistently loses 52 seconds for some reason.

I'd expect the times to match. Is my clock 52 seconds off a remote one it's referencing or something?

  • 写回答

2条回答 默认 最新

  • dongmei3869 2018-12-15 04:58
    关注

    Prior to September 1, 1906, your time zone difference was UTC-7:33:52. json.Unmarshal is just using the 7:33 in the marshaled text for the offset, instead of the correct value of 7:33:52, so the time.Time value it calculates is off by 52 seconds. But your time.Local implementation seems to be getting it right (to the extent we can describe backdating time zone differences to year 1 as "right") and subtracting the full 7:33:52 from the time.Time value, resulting in the difference you're seeing.

    If you output:

    fmt.Printf("Time A: %+v, Time B: %+v
    ", timeA.UTC(), timeB.UTC())
    

    with your current code you should see that the UTC time for timeB is getting set to 15:33:00 after unmarshaling, whereas the UTC time for timeA is getting set to 15:33:52. I suspect if you include a year after 1906 in your time string you'll see this 52 seconds difference disappear.

    For example:

    package main
    
    import (
        "encoding/json"
        "fmt"
        "log"
        "time"
    )
    
    func main() {
        zone, err := time.LoadLocation("America/Edmonton")
        if err != nil {
            log.Fatalf("%v", err)
        }
    
        for _, timestring := range []string{
            "01 02 1905 8:00",
            "01 02 1907 8:00",
        } {
            timeA, err := time.ParseInLocation("01 02 2006 15:04", timestring, zone)
            if err != nil {
                log.Fatalf("%v", err)
            }
    
            jBytes, _ := json.Marshal(timeA)
    
            var timeB time.Time
    
            json.Unmarshal(jBytes, &timeB)
    
            fmt.Printf("Time string: %s
    ", timestring)
            fmt.Printf("Time A: %+v, Time B: %+v
    ", timeA, timeB)
            fmt.Printf("Time A: %+v, Time B: %+v
    ", timeA.UTC(), timeB.UTC())
            fmt.Printf("Time A: %+v, Time B: %+v
    ", timeA.In(zone), timeB.In(zone))
            fmt.Printf("Diff: %s
    ", timeA.Sub(timeB))
            fmt.Printf("Marshaled: %s
    ", string(jBytes))
        }
    }
    

    outputs:

    paul@mac:got$ ./got
    Time string: 01 02 1905 8:00
    Time A: 1905-01-02 08:00:00 -0733 LMT, Time B: 1905-01-02 08:00:00 -0733 -0733
    Time A: 1905-01-02 15:33:52 +0000 UTC, Time B: 1905-01-02 15:33:00 +0000 UTC
    Time A: 1905-01-02 08:00:00 -0733 LMT, Time B: 1905-01-02 07:59:08 -0733 LMT
    Diff: 52s
    Marshaled: "1905-01-02T08:00:00-07:33"
    Time string: 01 02 1907 8:00
    Time A: 1907-01-02 08:00:00 -0700 MST, Time B: 1907-01-02 08:00:00 -0700 -0700
    Time A: 1907-01-02 15:00:00 +0000 UTC, Time B: 1907-01-02 15:00:00 +0000 UTC
    Time A: 1907-01-02 08:00:00 -0700 MST, Time B: 1907-01-02 08:00:00 -0700 MST
    Diff: 0s
    Marshaled: "1907-01-02T08:00:00-07:00"
    paul@mac:got$ 
    

    showing that the 52 second difference is there for 1905, but not for 1907 after the time zone difference changed to a straight UTC-7:00:00.

    Short answer: marshaling to and unmarshaling from json by default appears unable to correctly handle seconds in time zone offsets, because no seconds appear in the offset in the marshaled string and this is the only time zone information json.Unmarshal has available to it.

    For sure there is no referencing of clocks, remote or otherwise, in any of this code - it's just manipulating values.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 Stata链式中介效应代码修改
  • ¥15 latex投稿显示click download
  • ¥15 请问读取环境变量文件失败是什么原因?
  • ¥15 在若依框架下实现人脸识别
  • ¥15 网络科学导论,网络控制
  • ¥100 安卓tv程序连接SQLSERVER2008问题
  • ¥15 利用Sentinel-2和Landsat8做一个水库的长时序NDVI的对比,为什么Snetinel-2计算的结果最小值特别小,而Lansat8就很平均
  • ¥15 metadata提取的PDF元数据,如何转换为一个Excel
  • ¥15 关于arduino编程toCharArray()函数的使用
  • ¥100 vc++混合CEF采用CLR方式编译报错