2014-12-17 12 views
5

Mam problem z deserialising datetimes z Json.Net 6.0.3 (mogę replikować problem na 6.0.6). Kod jest uruchamiany w .Net 4.5 w Windows 8.1, a kultura to en-GB.Json.Net deserialising DateTimes niekonsekwentnie

To pokazuje problem:

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\"]"); 

wyjście:

{ 
    "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"] 

The data czasy różnią się w zależności od sposobu JObject jest dostępny - jedno jest MM/DD/YYYY DD/MM/YYYY. Dlaczego to?

Nie potrzebuję ich w określonym formacie: problem polega na tym, że format ulega zmianie. Mam dużo starszego kodu, który analizuje ciąg datetime pochodzący z Json.Net. Kod będzie również działał na różnych komputerach na całym świecie, być może w różnych kulturach.

Czy istnieje sposób, aby Json.Net zawsze zwracał liczbę dat w tym samym formacie?

Odpowiedz

7

Problem jest, że obie linie robić różne rzeczy:

jo["time"] 

jest (ostatecznie) pisanie rzeczywistą DateTime wartość do konsoli. Jako @JonSkeet points out, faktycznie piszesz JValue na konsolę - JValue.ToString just calls the wrapped value's ToString method though, która w twoim przypadku to DateTime.ToString().

Innymi słowy:

  • Wywołanie Console.WriteLine i przekazując instancję JValue używa przeciążenie Console.WriteLine że bierze object.
  • To przeciążenie Telefonowanie .ToString() na JValue
  • które następnie wywołuje .ToString() typu bazowego (w przypadku DateTime)

Więc masz zamiar dostać cokolwiek format domyślny dla bieżącej kultury . Dokładniej, otrzymasz DateTime sformatowany ze specyfikatorem "G" w aktualnej kulturze.

Bardziej interesujący jest wiersz jo.Value<string>("time"). Under the hood, JSON.NET jest przekształcenie stanowiącego podstawę DateTime na ciąg przy użyciu następujących:

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

To, oczywiście, daje zupełnie innyciąg, ponieważ jest jawnie przy użyciu CultureInfo.InvariantCulture.

wynos z tego jest to, że najlepiej jest prawdopodobnie pobierać datę jako DateTime, a następnie sformatować go dokładnie tak, jak chcesz, aby uniknąć wszelkich niejasności:

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

dobrze, pierwsza linia piszę 'JValue' na konsolę ... –

+0

@JonSkeet: Cóż, tak, upraszczałem to, ale metoda' ToString' 'JValue' wywołuje wartość bazową (w tym przypadku 'DateTime')' Metoda ToString'. –

+1

Dobrze. Byłbym niewygodny, gdybym był tobą. Podstawowa przesłanka jest w porządku (dlatego porzuciłem własną odpowiedź), ale dobrze jest precyzyjnie o tym mówić, gdy konwersje dotyczą całego miejsca. –

Powiązane problemy