Newtonsoft.Json无法解析冒号分隔毫秒的日期字符串问题
你遇到的核心问题是手动生成的时间字符串不符合ISO 8601标准,导致Newtonsoft.Json的默认解析器无法识别。下面详细拆解原因和解决方案:
问题重现
当你手动将DateTime格式化为带冒号分隔毫秒的字符串(如2018-05-27T04:59:40:887Z)并添加到JObject时,反序列化会抛出如下错误:
Newtonsoft.Json.JsonReaderException: Could not convert string to DateTimeOffset: 2018-05-27T04:59:40:887Z.
对应的错误代码:
public class TempClass { public DateTime TimeStamp { get; set; } } // 无法正常解析的代码 JObject jObject = new JObject(); jObject.Add("TimeStamp", DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss:fffZ")); TempClass chatMessage = JsonConvert.DeserializeObject<TempClass>(jObject.ToString());
而直接添加DateTime对象时,序列化和反序列化都能正常工作:
// 可正常解析的代码 JObject jObject = new JObject(); jObject.Add("TimeStamp", DateTime.Now); TempClass chatMessage = JsonConvert.DeserializeObject<TempClass>(jObject.ToString());
原因分析
ISO 8601标准规定,日期时间的小数秒部分必须用**点(.)或逗号(,)**分隔,而不是冒号(:)。你使用的格式符yyyy-MM-ddTHH:mm:ss:fffZ中,毫秒部分用了冒号,生成的是非标准格式字符串,Newtonsoft.Json的默认解析器不支持这种格式,因此抛出转换异常。
当你直接添加DateTime对象到JObject时,Newtonsoft.Json会自动将其序列化为符合ISO 8601标准的格式(如2018-05-27T04:59:40.887Z),所以反序列化能正常完成。
解决方案
方案1:优先直接添加DateTime对象(推荐)
避免手动格式化字符串,直接将DateTime或DateTimeOffset对象添加到JObject,让Newtonsoft.Json自动处理序列化格式。这是最简洁且不易出错的方式,就是你已经验证过的正常工作代码。
方案2:使用标准格式符生成时间字符串
如果必须手动生成时间字符串,修改格式符中的冒号为点:
// 正确的格式:用.分隔毫秒 string formattedTime = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"); jObject.Add("TimeStamp", formattedTime);
生成的字符串符合ISO 8601标准,能被Newtonsoft.Json正常解析。
方案3:自定义转换器处理非标准格式(针对特殊场景)
如果遇到服务器返回冒号分隔毫秒的非标准格式,可以自定义JsonConverter来兼容解析:
public class CustomDateTimeConverter : JsonConverter<DateTime> { private const string CustomFormat = "yyyy-MM-ddTHH:mm:ss:fffZ"; public override DateTime ReadJson(JsonReader reader, Type objectType, DateTime existingValue, bool hasExistingValue, JsonSerializer serializer) { string dateString = reader.Value.ToString(); return DateTime.ParseExact(dateString, CustomFormat, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal); } public override void WriteJson(JsonWriter writer, DateTime value, JsonSerializer serializer) { writer.WriteValue(value.ToString(CustomFormat)); } }
使用时在反序列化时指定转换器:
TempClass chatMessage = JsonConvert.DeserializeObject<TempClass>(jObject.ToString(), new CustomDateTimeConverter());
内容的提问来源于stack exchange,提问作者Nongthonbam Tonthoi

