Подход с использованием CustomInstantPattern
хорош, но я бы вообще не использовал любые типы даты / времени .NET.
Вместо этого я бы использовал два OffsetDateTimePattern
экземпляра, один с двоеточиями, а другой без, и комбинировал бы их с CompositePattern
. Затем вы можете просто делегировать это, преобразовав в / из Instant
, когда вам нужно.
Вот полный пример кода:
using Newtonsoft.Json;
using NodaTime;
using NodaTime.Serialization.JsonNet;
using NodaTime.Text;
using System;
using System.Text;
class CustomInstantPattern : IPattern<Instant>
{
private readonly IPattern<OffsetDateTime> offsetDateTimePattern;
public CustomInstantPattern()
{
// Pattern explanation:
// - o<G> means "use the G Offset pattern" (to hour, minute or second, with colons, format +00 as Z)
// - o<I> means "use the I Offset pattern" (to hour, minute or second, without colons, format +00 as Z)
var patternWithColon = OffsetDateTimePattern.CreateWithInvariantCulture("uuuu'-'MM'-'dd'T'HH':'mm':'ss;FFFFFFFFFo<G>");
var patternWithoutColon = OffsetDateTimePattern.CreateWithInvariantCulture("uuuu'-'MM'-'dd'T'HH':'mm':'ss;FFFFFFFFFo<I>");
offsetDateTimePattern = new CompositePatternBuilder<OffsetDateTime>()
{
// The predicates here are for formatting. As the first always
// returns true, it doesn't really matter what the second does.
// The intention is that some values might not be formattable with
// all patterns, but that doesn't apply here.
{ patternWithColon, _ => true },
{ patternWithoutColon, _ => true }
}.Build();
}
public StringBuilder AppendFormat(Instant value, StringBuilder builder) =>
offsetDateTimePattern.AppendFormat(value.WithOffset(Offset.Zero), builder);
public string Format(Instant value) =>
offsetDateTimePattern.Format(value.WithOffset(Offset.Zero));
public ParseResult<Instant> Parse(string text) =>
offsetDateTimePattern.Parse(text).Convert(odt => odt.ToInstant());
}
class Entity
{
public Instant I { get; set; }
}
class Program
{
static void Main(string[] args)
{
var settings = new JsonSerializerSettings
{
DateParseHandling = DateParseHandling.None,
Converters = { new NodaPatternConverter<Instant>(new CustomInstantPattern()) }
};
string json = " { \"i\": \"2018-10-25T18:34:11.911+0000\" }";
Entity entity = JsonConvert.DeserializeObject<Entity>(json, settings);
Console.WriteLine(entity.I);
// Check it works with colons too
json = " { \"i\": \"2018-10-25T18:34:11.911+00:00\" }";
entity = JsonConvert.DeserializeObject<Entity>(json, settings);
Console.WriteLine(entity.I);
}
}
(Это выявило две проблемы с Noda Time - одна из них заключается в том, что документация для встроенных партиалов неверна для шаблонов OffsetDateTime
, а другая - у нас нет стандартного шаблона для «расширенного ISO», что довольно раздражает. Постараюсь обратиться к обоим, когда смогу.)