如何将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
相关产品推荐
相关产品推荐

