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

前端 未结 1 1903
再見小時候
再見小時候 2020-12-10 23:10

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

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


        
相关标签:
1条回答
  • 2020-12-10 23:32

    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().

    0 讨论(0)
提交回复
热议问题