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

Golang单元测试:JSON反序列化time.Time字段异常求助

问题:Go单元测试中JSON日期字段解析为零值(0001-01-01)

我正在为Go服务编写单元测试,尝试用以下JSON模拟数据:

[
    {
        "Description": "Holiday 1",
        "HolidayDate": "2023-01-01T12:00:08+07:00"
    }
]

其中Description字段能正常解析,但HolidayDate字段解析后的值为0001-01-01 00:00:00 +0000 UTC。以下是我的代码,请问如何正确填充日期字段?

type Holiday struct {
    HolidayDate time.Time `json:"holidayDate"`
    Description string    `json:"description"`
}

func Ptr1[T any](v T) *T {
    return &v
}

func getMockData() ([]entities.Holiday, error) {
    holidayFilePath := filepath.Join("../adapters/repositories/mocks/testData", "holidays.json")

    mockHolidays, err := UnmarshalFileData[entities.Holiday](holidayFilePath)
    if err != nil {
        return nil, fmt.Errorf(holidayFilePath, err)
    }

    return mockHolidays, nil
}

func UnmarshalFileData[T any](filePath string) ([]T, error) {
    var data []T
    myFile, err := os.Open(filePath)
    if err != nil {
        return data, err
    }
    defer myFile.Close()
    err = json.NewDecoder(myFile).Decode(&data)
    if err != nil {
        return data, err
    }

    return data, nil
}

func TestMocks(t *testing.T) {
    mockHolidays, err := getMockData()
    holiday := time.Date(2023, time.Month(1), 1, 00, 00, 00, 0, time.UTC)

    if err != nil {
        t.Fatal("error mocking holiday data:", err)
    }
    fmt.Println(mockHolidays[0].HolidayDate.String(), holiday.String())
    assert.Equal(t, holiday.String(), mockHolidays[0].HolidayDate.String())
}

我尝试过多种JSON日期格式,但均未生效。


解决方案

1. 修正JSON标签与字段名的匹配问题

你的JSON中日期字段的键是HolidayDate(首字母大写),但结构体的JSON标签写的是holidayDate(首字母小写),导致encoding/json无法将JSON字段映射到结构体字段,因此HolidayDate被保留为time.Time的零值。

修改结构体的JSON标签,使其与JSON中的键完全一致:

type Holiday struct {
    HolidayDate time.Time `json:"HolidayDate"` // 改为大写H开头
    Description string    `json:"Description"` // 同步修正Description的标签,确保匹配
}

2. 调整测试断言的逻辑

修正标签后,JSON中的日期2023-01-01T12:00:08+07:00会被正确解析为time.Time类型,但该时间转换为UTC是2023-01-01 05:00:08 +0000 UTC,与你测试代码中创建的2023-01-01 00:00:00 +0000 UTC并不相等,断言会失败。

你可以选择两种方式调整:

  • 直接使用解析后的时间作为期望:
    // 解析后的UTC时间是2023-01-01 05:00:08 UTC
    expectedHoliday := time.Date(2023, time.January, 1, 5, 0, 8, 0, time.UTC)
    assert.Equal(t, expectedHoliday, mockHolidays[0].HolidayDate.UTC())
    
  • 或者比较时间的本地化值(如果业务需要保留时区):
    // 转换为+07:00时区的时间进行比较
    loc, _ := time.LoadLocation("Asia/Bangkok") // +07:00对应的时区
    expectedHoliday := time.Date(2023, time.January, 1, 12, 0, 8, 0, loc)
    assert.Equal(t, expectedHoliday, mockHolidays[0].HolidayDate)
    

3. 可选:自定义日期解析(针对非标准格式)

如果后续需要支持非RFC3339的日期格式,可以自定义类型并实现UnmarshalJSON方法:

type CustomTime time.Time

func (ct *CustomTime) UnmarshalJSON(b []byte) error {
    s := strings.Trim(string(b), "\"")
    // 替换为你需要支持的日期格式
    t, err := time.Parse("2006-01-02T15:04:05+07:00", s)
    if err != nil {
        return err
    }
    *ct = CustomTime(t)
    return nil
}

// 修改结构体字段类型
type Holiday struct {
    HolidayDate CustomTime `json:"HolidayDate"`
    Description string     `json:"Description"`
}

不过你的日期格式本身符合RFC3339标准,这一步不是必须的。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 08:03:08