2017-06-08 167 views
3

我看了很多相關的問題,但是他們都沒有爲我工作。Json.Net在序列化時爲DateTimeOffset弄亂了時區

我想序列化UTC中的所有東西。這裏是我的代碼:

class Class1 
{ 
    static void Main() 
    { 
     Class2 foo = new Class2(); 
     JObject json = JObject.Parse(JsonConvert.SerializeObject(foo, new JsonSerializerSettings() 
     { 
      DateParseHandling = DateParseHandling.DateTimeOffset, 
      DateFormatHandling = DateFormatHandling.IsoDateFormat, 
      DateTimeZoneHandling = DateTimeZoneHandling.Utc 
     })); 

     Console.WriteLine(json.ToString()); 

     Console.Read(); 
    } 
} 

class Class2 
{ 
    public DateTimeOffset time = new DateTimeOffset(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddTicks(14663484000000000)); 

    public DateTimeOffset time2 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddTicks(14663484000000000); 

    public DateTime time3 = new DateTime(14663484000000000); 
} 

這裏的輸出:

{ 
    "time": "2016-06-19T08:00:00-07:00", 
    "time2": "2016-06-19T08:00:00-07:00", 
    "time3": "0047-06-20T15:00:00Z" 
} 

這裏的我想要得到的輸出:

{ 
    "time": "2016-06-19T15:00:00+00:00", 
    "time2": "2016-06-19T15:00:00+00:00", 
    "time3": "0047-06-20T15:00:00+00:00" 
} 

正如你所看到的,DateTimeOffset性能不轉換在所有。 DateTime是,但時區使用Z表示,而我試圖使用+00:00

+0

爲什麼要將'foo'序列化爲JSON字符串,然後將字符串解析爲JToken層次結構,然後將層次結構重新序列化爲字符串以重現您的問題?如果您只是直接將'foo'序列化爲字符串,那麼時區信息是正確的,是嗎? – dbc

+0

@dbc我想爲序列化的JSON添加一些屬性,但是在試圖解決這個問題時我拿出了那部分內容。我到最後還是需要它。 – Zarwan

回答

5

在代碼中,你正在做以下幾點:

  1. 使用特定DateTime - 相關序列化設置,序列化的Class2一個實例JSON字符串。
  2. 反序列化爲JToken層級而不使用這些設置
  3. (製作其他修改層級 - 未示出)。
  4. 再次序列化JToken層級到最終串(通過json.ToString()),而不使用這些設置。

當您這樣做時,步驟#1中所選日期的格式設置會丟失。

爲了解決這個問題,每次從JSON字符串表示序列化或到JSON字符串表示時,都需要應用這些設置,因爲如this documentation page所解釋的,JSON沒有日期的「官方」格式。正因爲如此,JSON.NET將啓發式方法應用於識別和格式化日期,無論何時從JSON字符串表示形式轉換爲JSON字符串表示形式 - 您都只做了三次。

你可以做做到這一點:

var settings = new JsonSerializerSettings() 
{ 
    DateParseHandling = DateParseHandling.DateTimeOffset, 
    DateFormatHandling = DateFormatHandling.IsoDateFormat, 
    DateTimeZoneHandling = DateTimeZoneHandling.Utc 
}; 

// Generate initial serialization 
var initialString = JsonConvert.SerializeObject(foo, settings); 

// Parse back to JToken 
var json = JsonConvert.DeserializeObject<JObject>(initialString, settings); 

// Make modifications as required 
// json["foo"] = "bar"; 

// Generate final JSON. 
var finalString = JsonConvert.SerializeObject(json, Formatting.Indented, settings); 

爲了提高效率,你可以使用JToken.FromObject()(或JObject.FromObject()如果你喜歡)生成JToken層次結構,而不需要創建和分析一個初始的字符串表示:

var settings = new JsonSerializerSettings() 
{ 
    DateParseHandling = DateParseHandling.DateTimeOffset, 
    DateFormatHandling = DateFormatHandling.IsoDateFormat, 
    DateTimeZoneHandling = DateTimeZoneHandling.Utc 
}; 

var json = JToken.FromObject(foo, JsonSerializer.CreateDefault(settings)); 

// Make modifications as required 
// json["foo"] = "bar"; 

// Generate final JSON. 
var finalString = JsonConvert.SerializeObject(json, Formatting.Indented, settings); 

但是請注意,這Json.NET將輸出一個UTC DateTime格式"0047-06-20T15:00:00Z"而不是"2016-06-19T15:00:00+00:00"原因解釋爲here。如果您需要將UTC DateTime屬性以DateTimeOffset格式序列化,則可能需要使用custom converter

+0

很好的答案,謝謝 – Zarwan