Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
335 views
in Technique[技术] by (71.8m points)

c# - How to convert new Date(year, month, day) overload with JSON.Net

I'm trying to parse JSON file where dates are defined as JavaScript objects :

new Date(year, month[, day[, hour[, minutes[, seconds[, milliseconds]]]]]);

so I did try to parse it with the JavaScriptDateTimeConverter

test.json:

{"data" : [{"Date" : new Date(2015, 06, 01, 00, 00, 00)}]}

c#:

using (StreamReader file = File.OpenText(@"c:est.json"))
{
  JsonSerializer serializer = new JsonSerializer();
  serializer.Converters.Add(new JavaScriptDateTimeConverter());
  Rootobject deserializedRoot = (Rootobject)serializer.Deserialize(file, typeof(Rootobject));
}

Unfortunatly I'm receiving this error :

Unexpected token parsing date. Expected EndConstructor, got Integer. Path 'data[0].Date1', line 13, position 30.

From my understanding JSON.Net expect at best a new Date(52231943) but doesn't handle constructor overloads of Javascript Date() object.

Is there any known way to convert the new Date(year, month, day)?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You could create your own subclass of JavaScriptDateTimeConverter.cs like so:

public class JavaScriptYMDDateTimeConverter : JavaScriptDateTimeConverter
{
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        Type type = (Nullable.GetUnderlyingType(objectType) ?? objectType);
        bool isNullable = (Nullable.GetUnderlyingType(objectType) != null);

        var token = JToken.Load(reader);
        if (token == null || token.Type == JTokenType.Null)
        {
            if (!isNullable)
                throw new JsonSerializationException(string.Format("Null value for type {0} at path {1}", objectType.Name, reader.Path));
            return null;
        }
        if (token.Type != JTokenType.Constructor)
        {
            throw new JsonSerializationException(string.Format("Invalid Date constructor "{0}" at path {1}", token.ToString(), reader.Path));
        }
        var constructor = (JConstructor)token;
        if (!string.Equals(constructor.Name, "Date", StringComparison.Ordinal))
        {
            throw new JsonSerializationException(string.Format("Invalid Date constructor "{0}" at path {1}", token.ToString(), reader.Path));
        }

        var values = constructor.Values().ToArray();

        if (values.Length == 0)
        {
            throw new JsonSerializationException(string.Format("Invalid Date constructor "{0}" at path {1}", token.ToString(), reader.Path));
        }
        else if (values.Length == 1)
        {
            // Assume ticks
            using (var subReader = constructor.CreateReader())
            {
                while (subReader.TokenType != JsonToken.StartConstructor)
                    subReader.Read();
                return base.ReadJson(subReader, objectType, existingValue, serializer); // Use base class to convert
            }
        }
        else
        {
            var year = (values.Length > 0 ? (int)values[0] : 0);
            var month = (values.Length > 1 ? (int)values[1] : 0) + 1; // c# months go from 1 to 12, JavaScript from 0 to 11
            var day = (values.Length > 2 ? (int)values[2] : 0);
            var hour = (values.Length > 3 ? (int)values[3] : 0);
            var min = (values.Length > 4 ? (int)values[4] : 0);
            var sec = (values.Length > 5 ? (int)values[5] : 0);
            var ms = (values.Length > 6 ? (int)values[6] : 0);

            // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date
            // Note: Where Date is called as a constructor with more than one argument, the specifed arguments represent local time.
            var dt = new DateTime(year, month, day, hour, min, sec, ms, DateTimeKind.Local);
            if (type == typeof(DateTimeOffset))
                return new DateTimeOffset(dt);
            return dt;
        }
    }
}

Here ReadJson() loads the token into a JConstructor, checks that the constructor name is Date, then parses the children.

Note I did not override WriteJson, so this converter will write in the same style as JavaScriptDateTimeConverter, with the ticks appearing as the single argument to the constructor.

Use it in place of JavaScriptDateTimeConverter().


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...