使用NewtonsoftJson在控制器中读取原始JSON DateTime值并移除时区
解决DateTime DTO属性移除时区信息的问题
问题核心
你遇到的问题是Newtonsoft.Json默认会自动将带时区的日期字符串转换为本地时区的DateTime对象,导致自定义转换器的ReadJson方法中无法获取原始的JSON字符串值。下面提供两种可行的解决方案:
方案1:自定义转换器(精准控制)
直接在转换器中读取原始的日期字符串,截断时区部分后再解析为DateTime:
public class DateTimeWithoutTimeZoneConverter : DateTimeConverterBase { public override bool CanConvert(Type objectType) { return objectType == typeof(DateTime) || objectType == typeof(DateTime?); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { // 仅处理字符串类型的日期节点 if (reader.TokenType != JsonToken.String) { return objectType == typeof(DateTime?) ? null : DateTime.MinValue; } var rawDateStr = reader.Value.ToString(); // 定位时区分隔符(+/-),截断字符串 var zoneSeparatorIndex = rawDateStr.IndexOfAny(new[] { '+', '-' }); if (zoneSeparatorIndex > 0) { rawDateStr = rawDateStr.Substring(0, zoneSeparatorIndex); } // 解析为DateTime,指定Kind为Unspecified(避免自动时区转换) if (DateTime.TryParse(rawDateStr, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime result)) { return objectType == typeof(DateTime?) ? (object?)result : result; } // 解析失败返回默认值(可根据需求抛出异常) return objectType == typeof(DateTime?) ? null : DateTime.MinValue; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { // 序列化时输出不带时区的标准格式 if (value is DateTime date) { writer.WriteValue(date.ToString("yyyy-MM-ddTHH:mm:ss.fff", CultureInfo.InvariantCulture)); } else if (value is DateTime? nullableDate && nullableDate.HasValue) { writer.WriteValue(nullableDate.Value.ToString("yyyy-MM-ddTHH:mm:ss.fff", CultureInfo.InvariantCulture)); } else { writer.WriteNull(); } } }
注册方式保持你之前的代码即可:
services.AddControllers() .AddNewtonsoftJson(options => options.SerializerSettings.Converters.Add(new DateTimeWithoutTimeZoneConverter()))
原理说明
通过检查JsonReader.TokenType是否为JsonToken.String,直接读取原始的日期字符串,而非已经被Newtonsoft转换后的DateTime对象,这样就能手动截断时区部分,得到你需要的纯日期时间值。
方案2:全局配置(快速生效)
如果不需要精准控制单个属性,可直接通过Newtonsoft的全局配置忽略时区:
services.AddControllers() .AddNewtonsoftJson(options => { // 反序列化时忽略时区,将日期解析为Unspecified类型的DateTime options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Unspecified; // 序列化时同样输出不带时区的格式 options.SerializerSettings.DateFormatString = "yyyy-MM-ddTHH:mm:ss.fff"; });
优缺点
- 优点:无需编写自定义转换器,配置简单,全局生效
- 缺点:所有DateTime类型的序列化/反序列化都会忽略时区,无法针对单个属性做特殊处理
内容的提问来源于stack exchange,提问作者ilyazakharov
相关产品推荐
相关产品推荐

