如何使用NodaTime和System.Text.Json反序列化无末尾Z的Instant?
解决NodaTime Instant解析无Z后缀UTC时间的问题
默认情况下,NodaTime的System.Text.Json转换器要求UTC时间字符串符合ISO 8601标准(带有Z后缀),而你的JSON时间字符串缺少Z,导致解析失败。以下是两种可行的解决方案:
方案一:自定义Instant转换器
实现一个自定义的JsonConverter,直接解析不带Z的UTC时间字符串:
public class InstantWithoutZConverter : JsonConverter<Instant> { // 定义匹配无Z后缀的UTC时间格式 private static readonly InstantPattern _parsePattern = InstantPattern.CreateWithInvariantCulture("yyyy-MM-dd'T'HH:mm:ss"); public override Instant Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var dateStr = reader.GetString() ?? throw new JsonException("时间字符串为空"); var parseResult = _parsePattern.Parse(dateStr); if (!parseResult.Success) throw new JsonException($"解析Instant失败:{parseResult.ErrorMessage}"); return parseResult.Value; } public override void Write(Utf8JsonWriter writer, Instant value, JsonSerializerOptions options) { // 序列化时输出标准带Z的格式 writer.WriteStringValue(value.ToString("o", CultureInfo.InvariantCulture)); } }
使用时替换默认转换器:
var options = new JsonSerializerOptions() .ConfigureForNodaTime(DateTimeZoneProviders.Tzdb); // 移除默认的Instant转换器,添加自定义转换器 var defaultInstantConverter = options.Converters.First(c => c.CanConvert(typeof(Instant))); options.Converters.Remove(defaultInstantConverter); options.Converters.Add(new InstantWithoutZConverter()); var item = JsonSerializer.Deserialize<Item>(jsonString, options);
方案二:修改默认转换器的解析模式
直接修改NodaTime默认转换器的时间匹配模式,无需自定义转换器:
var options = new JsonSerializerOptions() .ConfigureForNodaTime(DateTimeZoneProviders.Tzdb); // 获取默认的Instant转换器并更新解析模式 var instantConverter = (NodaTimeJsonConverter<Instant>)options.Converters.First(c => c.CanConvert(typeof(Instant))); instantConverter.Pattern = InstantPattern.CreateWithInvariantCulture("yyyy-MM-dd'T'HH:mm:ss"); var item = JsonSerializer.Deserialize<Item>(jsonString, options);
两种方案都能安全解析无Z后缀的UTC时间(前提是你确认输入时间确实为UTC),方案一更灵活,适合需要额外处理逻辑的场景;方案二更简洁,仅修改现有配置即可。
内容的提问来源于stack exchange,提问作者mcont
相关产品推荐
相关产品推荐

