Json.Net deserializing DateTimes непоследовательно

98
8

У меня возникли проблемы с десериализацией datetimes с Json.Net 6.0.3 (я могу воспроизвести проблему в версии 6.0.6). Код запускается в .Net 4.5 в Windows 8.1, а культура - en-GB.


Это демонстрирует проблему:


using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

var d1 = new DateTimeOffset(2014, 12, 15, 18, 0, 0, TimeSpan.FromHours(1));
var obj = new {
time = d1
};

var json = JsonConvert.SerializeObject(obj, Formatting.Indented);
Console.WriteLine(json);

var jo = JObject.Parse(json);

Console.WriteLine(jo.Value<string>("time") + " // jo.Value<string>(\"time\")");
Console.WriteLine(jo["time"] + " // jo[\"time\"]");


вывод:


{
"time": "2014-12-15T18:00:00+01:00"
}
12/15/2014 17:00:00 // jo.Value<string>("time")
15/12/2014 17:00:00 // jo["time"]

Время даты различно в зависимости от способа доступа к объекту JObject - один из них - MM/DD/YYYY DD/MM/YYYY. Почему это?


Мне не нужны они в определенном формате: проблема в том, что формат меняется. У меня много устаревшего кода, который анализирует строку datetime, полученную из Json.Net. Код также будет работать на разных компьютерах по всему миру, возможно, с разными культурами.


Есть ли способ заставить Json.Net всегда возвращать datetime в том же формате?

спросил(а) 2014-12-17T18:58:00+03:00 5 лет, 9 месяцев назад
1
Решение
114

Проблема в том, что две строки имеют разные вещи:


jo["time"]

Является (в конечном счете) записывает фактическое значение DateTime на консоль. Поскольку @JonSkeet указывает на, вы на самом деле пишете JValue на консоли - JValue.ToString просто вызывает метод завершенного значения ToString, хотя, что в вашем случае DateTime.ToString().


Другими словами:


    Вызов Console.WriteLine и передача экземпляра JValue использует перегрузку Console.WriteLine, которая принимает object.
    Перегрузка вызовов .ToString() на JValue
    который затем вызывает .ToString() в базовом типе (в вашем случае a DateTime)

Итак, вы получите какой-либо формат по умолчанию для вашей текущей культуры. Более конкретно, вы собираетесь получить DateTime в формате "G" в вашей текущей культуре.

Более интересным битом является строка jo.Value<string>("time"). Под капотом, JSON.NET преобразует базовый DateTime в строку, используя следующее:


Convert.ChangeType(value, typeof(string), CultureInfo.InvariantCulture);

Это, конечно, создает совершенно другую строку, так как она явно использует CultureInfo.InvariantCulture.


Вывод из этого состоит в том, что лучший выбор - это, вероятно, получить дату как DateTime, а затем отформатировать ее точно так, как вы хотите, чтобы избежать какой-либо двусмысленности:


DateTime dt = jo.Value<DateTime>("time");
string dateTimeSTring = dt.ToString(/* whatever format you always want */);

ответил(а) 2014-12-17T19:13:00+03:00 5 лет, 9 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема