NodaTime UnparsableValueException由于使用" Z" in pattern

时间:2017-04-06 19:11:47

标签: nodatime

我在Java和C#之间交换JSON消息(反之亦然)。

在Java中,我使用java.time.Instant(JSR-310)来表示全局时间轴上的某个时间点。为了在JSON中创建人类可读的日期/时间字符串,我将我的Instant转换如下:

private static final DateTimeFormatter FORMATTER = ofPattern("yyyy-MM-dd'T'HH:mm:ssZ").withZone(ZoneId.systemDefault());

生成以下输出:

2017-04-28T19:54:44-0500

现在,在消息的消费者方面(C#),我编写了一个自定义的Newtonsoft.Json.JsonConverter,它扩展了包含以下重写的ReadJson()方法的抽象JsonCreationConvert类:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
        JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
        {
            return null;
        }

        if (reader.TokenType == JsonToken.StartArray)
        {
            return JToken.Load(reader).ToObject<string[]>();
        }

        reader.DateParseHandling = DateParseHandling.None; // read NodaTime string Instant as is
        serializer.Converters.Add(NodaConverters.InstantConverter);

        // Load JObject from stream
        var jObject = JObject.Load(reader);

        // Create target object based on JObject
        T target = Create(objectType, jObject);

        // Populate the object properties
        var writer = new StringWriter();
        serializer.Serialize(writer, jObject);
        using (var newReader = new JsonTextReader(new StringReader(writer.ToString())))
        {
            newReader.Culture = reader.Culture;
            newReader.DateParseHandling = reader.DateParseHandling;
            newReader.DateTimeZoneHandling = reader.DateTimeZoneHandling;
            newReader.FloatParseHandling = reader.FloatParseHandling;
            serializer.Populate(newReader, target);
        }

        return target;
    }

Create()是一种抽象方法。

当我现在通过调用:

将此JSON字符串转换为NodaTime.Instant(v2.0.0)时
InstantPattern.General.Parse(creationTime).Value;

我得到了这个例外:

NodaTime.Text.UnparsableValueException: The value string does not match a quoted string in the pattern. Value being parsed: '2017-04-28T19:54:44^-0500'. (^ indicates error position.)

如果我传递文字文字&#34; Z&#34; (因此没有输出偏移&#34; -0500&#34;并且Z被解释为0偏移)NodaTime.Serialization.JsonNet.NodaConverters.InstantConverter正确读取而不抛出异常。

查看GeneralPatternImpl我看到:

internal static readonly InstantPattern GeneralPatternImpl = InstantPattern.CreateWithInvariantCulture("uuuu-MM-ddTHH:mm:ss'Z'");

为什么InstantConverter要求偏移量是文本字面值?这是否发生是因为Instant与偏移量无关?如果是这种情况,那么为什么InstantConverter不会忽略偏移而不是抛出异常?我是否需要编写自定义转换器来解决此问题?

1 个答案:

答案 0 :(得分:1)

这就像要求2017-04-28T19:54:44被解析为LocalDate一样 - 我们会默默地删除那些额外的信息。从根本上说,您在Java中从InstantString的转换是&#34;添加&#34;在原始时刻内并不存在的信息。您最终得到的内容实际上是OffsetDateTime,而不是Instant - 它提供的信息比Instant更多。

您应该决定您真正关心的信息。如果您只关心当前的时间,那么将您的Java序列化更改为使用UTC,它应该以序列化形式结束Z,一切都会好的。这就是我建议你做的事 - 传播无关的信息会产生误导,IMO。

如果您确实关心系统默认时区中的偏移量,而您对.withZone(ZoneId.systemDefault()) 的调用暗示,那么您应该将其解析为OffsetDateTime on事物的.NET方面。如果您愿意,可以将其转换为Instant(只需致电ToInstant())。