You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go中自定义Time结构体MarshalJSON未转换UTC时间的原因

问题:自定义Time结构体的MarshalJSON方法未生效

我尝试定义一个实现Marshaler接口的Time结构体,使其序列化为JSON时以YYYY-mm-ddTHH:MM:SSZ格式呈现(转换为UTC时间并四舍五入到最近秒数),编写了如下代码:

package main

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

type Time struct {
    time.Time
}

func (t *Time) MarshalJSON() ([]byte, error) {
    return []byte(t.Time.UTC().Round(time.Second).Format(time.RFC3339)), nil
}

func main() {
    tm := time.Now()
    // tm := time.Now().UTC().Round(time.Second)

    tmJSON, err := json.Marshal(tm)
    if err != nil {
        log.Fatalf("marshal time: %v", err)
    }

    fmt.Println(string(tmJSON))
}

运行程序后输出:

> go run main.go
"2022-12-07T16:32:51.494597-08:00"

若改用注释行的输入time.Now().UTC().Round(time.Second),输出符合预期:

> go run main.go
"2022-12-08T00:41:10Z"

为什么无法在MarshalJSON方法内直接完成UTC转换和秒级四舍五入操作?


原因与修复方案

核心原因:序列化对象类型不匹配

你在main中创建的tm是标准库的time.Time类型,而非自定义的Time结构体。json.Marshal会根据传入对象的类型调用对应实现的MarshalJSON方法——这里执行的是标准库time.Time自带的序列化逻辑,完全没触发你自定义的方法。

次要问题:JSON格式错误

你自定义的MarshalJSON返回的字符串没有添加双引号,直接返回格式字符串会导致生成的JSON不符合规范(标准库序列化time.Time时会自动添加双引号)。

修正后的代码

package main

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

type Time struct {
    time.Time
}

// 改为值接收者,避免空指针问题(可选,但更健壮)
func (t Time) MarshalJSON() ([]byte, error) {
    // 给格式化后的UTC时间字符串添加双引号,符合JSON语法
    formattedStr := fmt.Sprintf(`"%s"`, t.UTC().Round(time.Second).Format(time.RFC3339))
    return []byte(formattedStr), nil
}

func main() {
    // 使用自定义Time类型包裹标准time.Time实例
    tm := Time{Time: time.Now()}

    tmJSON, err := json.Marshal(tm)
    if err != nil {
        log.Fatalf("marshal time: %v", err)
    }

    fmt.Println(string(tmJSON))
}

运行修正后的代码,即可得到预期的"YYYY-mm-ddTHH:MM:SSZ"格式输出。


内容的提问来源于stack exchange,提问作者Kurt Peek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 07:10:28