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 phython如何实现以下功能?查找同一用户名的消费金额合并—
  • ¥15 孟德尔随机化怎样画共定位分析图
  • ¥18 模拟电路问题解答有偿速度
  • ¥15 CST仿真别人的模型结果仿真结果S参数完全不对
  • ¥15 误删注册表文件致win10无法开启
  • ¥15 请问在阿里云服务器中怎么利用数据库制作网站
  • ¥60 ESP32怎么烧录自启动程序
  • ¥50 html2canvas超出滚动条不显示
  • ¥15 java业务性能问题求解(sql,业务设计相关)
  • ¥15 52810 尾椎c三个a 写蓝牙地址