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 poi合并多个word成一个新word,原word中横版没了.
  • ¥15 【火车头采集器】搜狐娱乐这种列表页网址,怎么采集?
  • ¥15 求MCSCANX 帮助
  • ¥15 机器学习训练相关模型
  • ¥15 Todesk 远程写代码 anaconda jupyter python3
  • ¥15 我的R语言提示去除连锁不平衡时clump_data报错,图片以下所示,卡了好几天了,苦恼不知道如何解决,有人帮我看看怎么解决吗?
  • ¥15 在获取boss直聘的聊天的时候只能获取到前40条聊天数据
  • ¥20 关于URL获取的参数,无法执行二选一查询
  • ¥15 液位控制,当液位超过高限时常开触点59闭合,直到液位低于低限时,断开
  • ¥15 marlin编译错误,如何解决?