2015-07-23 3 views
0

Я пытаюсь разобрать файл JSON, где дата определяется как JavaScript objects:Как преобразовать новую дату (год, месяц, день) перегрузки с Json.NET

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

так что я пытаюсь разобрать его с JavaScriptDateTimeConverter

test.json:

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

C#:

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

Unfortunatly Я получаю эту ошибку:

Неожиданный маркер даты синтаксического анализа. Ожидаемый EndConstructor, получил Integer. Path 'данных [0] .Date 1', строка 13, позиция 30.

Из моего понимания Json.NET ожидать в лучшем случае new Date(52231943) но не обрабатывает конструктор перегруженные Javascript Date() объекта.

Есть ли какой-либо известный способ преобразования new Date(year, month, day)?

+0

В файле, который вы обрабатываете, эти даты всегда содержатся в массиве, как указано выше? –

+0

Обратите внимание, что это на самом деле не законный «json» - http://json.org. Это может быть действительный объект Javascript, но не json. –

+0

@ LasseV.Karlsen - вы правы, тем не менее Json.NET поддерживает такой синтаксис. См. Http://james.newtonking.com/archive/2009/02/20/good-date-times-with-json-net и http://www.newtonsoft.com/json/help/html/DatesInJSON.htm – dbc

ответ

1

Вы можете создать свой собственный подкласс JavaScriptDateTimeConverter.cs так:

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

Здесь ReadJson() загружают лексемы в JConstructor, проверяет, что constructor name является Date, затем разбирает ребенок.

Примечание. Я не переопределял WriteJson, поэтому этот конвертер будет писать в том же стиле, что и JavaScriptDateTimeConverter, причем тики появляются в качестве единственного аргумента конструктору.

Используйте его вместо JavaScriptDateTimeConverter().

+0

Работает так, как ожидалось, кроме JToken.Load() обрабатывает ведущие нули от 00 до 07, но падает с 08 и 09. Я исправляю его с помощью: var json = Regex.Replace (input, "() 0 * ([1-9 ] [0-9] * | 0) "," $ 1 $ 2 "); –

+0

@ lucian.jp - Рад, что он работает на вас. Не могли бы вы поделиться примером JSON, который вызывает крах? – dbc

+0

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

Смежные вопросы