代码之家  ›  专栏  ›  技术社区  ›  Paulo Morgado

如何解析“uuu”-“MM”-“dd'T'HH”:“MM”:“ss;一瞬间?

  •  0
  • Paulo Morgado  · 技术社区  · 6 年前

    我有一门课:

    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 回复  |  直到 6 年前
        1
  •  4
  •   Jon Skeet    6 年前

    使用 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);
        }
    }
    

    OffsetDateTime 模式,其中一个是我们没有一个标准的“扩展ISO”模式,这很烦人。当我可以的时候,我会尽量解决这两个问题。)

        2
  •  0
  •   Paulo Morgado    6 年前

    我可以用一种特殊的模式来解决这个问题:

    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);