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

如何将API返回的JSON日期对象转换为DateTime类型?

如何将包含day/month/year的日期对象反序列化为DateTime类型?

当API返回的日期是包含day/month/year字段的嵌套对象时,直接用DateTime类型反序列化会失败——因为System.Text.Json默认不支持这种结构的映射。以下是两种最优解决方法:

方法一:自定义JsonConverter(推荐)

通过实现自定义JSON转换器,统一处理这种日期结构的反序列化(和序列化)逻辑,可全局复用,代码更简洁。

1. 实现日期转换器

public class DayMonthYearToDateTimeConverter : JsonConverter<DateTime>
{
    public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        using var jsonDoc = JsonDocument.ParseValue(ref reader);
        var root = jsonDoc.RootElement;
        
        var day = root.GetProperty("day").GetInt32();
        var month = root.GetProperty("month").GetInt32();
        var year = root.GetProperty("year").GetInt32();

        // 兼容特殊年份(如示例中的32767,超过DateTime最大年份9999)
        if (year > DateTime.MaxValue.Year)
        {
            return DateTime.MaxValue;
        }

        return new DateTime(year, month, day);
    }

    public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
    {
        // 如需将DateTime序列化为day/month/year结构,可实现此方法
        writer.WriteStartObject();
        writer.WriteNumber("day", value.Day);
        writer.WriteNumber("month", value.Month);
        writer.WriteNumber("year", value.Year);
        writer.WriteEndObject();
    }
}

2. 使用转换器

有两种使用方式:

方式A:全局配置(适用于多个实体类需要处理该日期结构的场景)

在反序列化时传入配置好的JsonSerializerOptions:

var options = new JsonSerializerOptions();
options.Converters.Add(new DayMonthYearToDateTimeConverter());

var countries = await JsonSerializer.DeserializeAsync<List<Country>>(contentStream, options);

方式B:实体类字段标记(仅针对当前字段生效)

直接在Country类的DateTime字段上添加[JsonConverter]属性:

public class Country {
    [JsonPropertyName("countryCode")]
    public string CountryCode { get; set; }

    [JsonPropertyName("regions")]
    public List<string> Regions { get; set; }

    [JsonPropertyName("holidayTypes")]
    public List<string> HolidayTypes { get; set; }

    [JsonPropertyName("fullName")]
    public string FullName { get; set; }

    [JsonPropertyName("fromDate")]
    [JsonConverter(typeof(DayMonthYearToDateTimeConverter))]
    public DateTime FromDate { get; set; }

    [JsonPropertyName("toDate")]
    [JsonConverter(typeof(DayMonthYearToDateTimeConverter))]
    public DateTime ToDate { get; set; }
}

方法二:中间DTO映射

如果不想自定义转换器,可以先定义一个和API返回结构完全匹配的中间DTO类,反序列化后再手动转换为目标实体类。

1. 定义中间DTO类

public class CountryDto {
    [JsonPropertyName("countryCode")]
    public string CountryCode { get; set; }

    [JsonPropertyName("regions")]
    public List<string> Regions { get; set; }

    [JsonPropertyName("holidayTypes")]
    public List<string> HolidayTypes { get; set; }

    [JsonPropertyName("fullName")]
    public string FullName { get; set; }

    [JsonPropertyName("fromDate")]
    public DateObject FromDate { get; set; }

    [JsonPropertyName("toDate")]
    public DateObject ToDate { get; set; }
}

public class DateObject {
    public int Day { get; set; }
    public int Month { get; set; }
    public int Year { get; set; }
}

2. 反序列化并转换

var countryDtos = await JsonSerializer.DeserializeAsync<List<CountryDto>>(contentStream);
var countries = countryDtos.Select(dto => new Country {
    CountryCode = dto.CountryCode,
    Regions = dto.Regions,
    HolidayTypes = dto.HolidayTypes,
    FullName = dto.FullName,
    FromDate = new DateTime(dto.FromDate.Year, dto.FromDate.Month, dto.FromDate.Day),
    ToDate = dto.ToDate.Year > DateTime.MaxValue.Year 
        ? DateTime.MaxValue 
        : new DateTime(dto.ToDate.Year, dto.ToDate.Month, dto.ToDate.Day)
}).ToList();

方案对比

  • 自定义转换器:最优解,逻辑统一可复用,支持序列化和反序列化双向处理,适合长期维护的项目。
  • 中间DTO映射:无需额外编写转换器,适合临时场景或简单需求,但代码冗余度较高,无法全局复用转换逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 08:15:42