Json.Net在序列化时弄乱了DateTimeOffset的时区

时间:2017-06-08 03:36:44

标签: c# datetime serialization 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 个答案:

答案 0 :(得分:9)

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

  1. 使用特定的Class2相关序列化设置将DateTime的实例序列化为JSON字符串。
  2. 在不使用这些设置的情况下反序列化为JToken层次结构
  3. (对层次结构进行其他修改 - 未显示。)
  4. 在不使用这些设置的情况下,再次将JToken层次结构序列化为最终字符串(通过json.ToString())。
  5. 执行此操作时,步骤1中所选日期的格式设置将丢失。

    要解决此问题,您需要在每次从JSON字符串表示序列化时应用设置,因为,如this documentation page中所述,JSON没有"官方"日期格式。因此,当JSON.NET从JSON字符串表示转换为JSON字符串表示时,Json.NET会应用启发式方法识别和格式化日期 - 您不是一次而是三次。

    您可以通过以下方式完成此任务:

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

    但请注意,由于here解释的原因,Json.NET将以DateTime格式而不是"0047-06-20T15:00:00Z"格式输出UTC "2016-06-19T15:00:00+00:00"。如果您需要以DateTime格式序列化UTC DateTimeOffset属性,则可能需要使用custom converter