Как преобразовать "uuuu" - 'MM' - 'dd'T'HH': 'mm': 'ss; FFFFFFFFFo <Z + HHmm> "в мгновение? - PullRequest
0 голосов
/ 26 октября 2018

У меня есть этот класс:

public class Test
{
    public Instant I { get; set;}
}

I - это Instant, потому что это то, что имеет смысл семантически.

Однако я должен десериализовать его из этого:

{
    "i": "2018-10-25T18:34:11.911+00:00"
}

и из этого:

{
    "i": "2018-10-25T18:34:11.911+0000"
}

Как я могу это сделать?

Ответы [ 2 ]

0 голосов
/ 28 октября 2018

Подход с использованием 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», что довольно раздражает. Постараюсь обратиться к обоим, когда смогу.)

0 голосов
/ 26 октября 2018

Мне удалось обойти это, используя специальный шаблон:

public class CustomInstantPattern : IPattern<Instant>
{
    public StringBuilder AppendFormat(Instant value, StringBuilder builder)
    {
        return builder.AppendFormat("s", value.ToDateTimeOffset());
    }

    public string Format(Instant value)
    {
        return value.ToDateTimeOffset().ToString("s");
    }

    public ParseResult<Instant> Parse(string text)
    {
        try
        {
            return ParseResult<Instant>.ForValue(DateTimeOffset.Parse(text, CultureInfo.InvariantCulture).ToInstant());
        }
        catch (Exception ex)
        {
            return ParseResult<Instant>.ForException(() => throw ex);
        }
    }
}

var settings = new JsonSerializerSettings
{
    DateParseHandling = DateParseHandling.None,
    Converters =
    {
        new NodaPatternConverter<Instant>(new CustomInstantPattern()),
    }
};

var converted = JsonConvert.DeserializeObject<Test>("{ 'I': '2018-10-25T18:34:11.911+0000'}", settings);

Это правильный путь?

...