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

在您的代码中,您正在执行以下操作:

  1. 使用特定的与DateTime相关的序列化设置将Class2的实例序列化为JSON字符串。
  2. 不使用这些设置的情况下反序列JToken层次结构。
  3. (对层次结构进行其他修改 – 未显示。)
  4. 在不使用这些设置的情况下,再次将JToken层次结构序列JToken最终字符串(通过json.ToString() )。

执行此操作时,步骤1中选择的日期的格式设置将丢失。

要解决此问题,您需要在每次从JSON字符串表示序列化时应用设置,因为,如本文档页面中所述 ,JSON没有日期的“官方”格式。 因此,Json.NET应用启发式方法来识别和格式化日期,只要它转换为JSON字符串表示forms – 您不是一次而是三次。

你可以这样做:

 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(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将以"0047-06-20T15:00:00Z"格式输出UTC DateTime ,而不是"2016-06-19T15:00:00+00:00" ,原因如下所述。 如果需要以DateTimeOffset格式序列化UTC DateTime属性,则可能需要使用自定义转换器 。