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 C# 调用Bartender打印机打印
  • ¥100 华为ensp只要2-9实验运行结果能做的来加我QQ
  • ¥15 我这个代码哪里有问题 acm 平台上显示错误 90%,我自己运行好像没什么问题
  • ¥50 C#编程中使用printDocument类实现文字排版打印问题
  • ¥15 找会编程的帅哥美女 可以用MATLAB里面的simulink编程,用Keil5编也可以。
  • ¥15 已知隐函数其中一个变量τ的具体值,求另一个变量
  • ¥15 r语言Hurst指数
  • ¥15 Acrn IVSHMEM doorbell问题
  • ¥15 yolov5中的val测试集训练时数量变小问题
  • ¥15 MPLS/VPN实验中MPLS的配置问题