Json.Net 在序列化时弄乱了 DateTimeOffset 的时区
Json.Net messes up timezones for DateTimeOffset when serializing
我已经查看了很多相关问题,但其中 none 似乎对我有用。
我正在尝试以 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
.
在您的代码中,您正在执行以下操作:
- 使用特定的
DateTime
相关序列化设置将 Class2
的实例序列化为 JSON 字符串。
- 在不使用这些设置的情况下反序列化为
JToken
层次结构 。
- (对层次结构进行其他修改 - 未显示。)
- 在不使用这些设置的情况下再次将
JToken
层次结构序列化为最终字符串(通过 json.ToString()
)。
当您这样做时,在第 1 步中选择的日期格式设置会丢失。
要解决这个问题,您需要在每次从 JSON 字符串表示序列化或向 JSON 字符串表示序列化时应用设置,因为,如 this documentation page 中所述,JSON 没有日期的 "official" 格式。正因为如此,Json.NET 应用启发式方法来识别和格式化日期,每当它从 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()
(or 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"
原因 . If you need your UTC DateTime
properties to be serialized in DateTimeOffset
format you might need to use a custom converter。
我已经查看了很多相关问题,但其中 none 似乎对我有用。
我正在尝试以 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
.
在您的代码中,您正在执行以下操作:
- 使用特定的
DateTime
相关序列化设置将Class2
的实例序列化为 JSON 字符串。 - 在不使用这些设置的情况下反序列化为
JToken
层次结构 。 - (对层次结构进行其他修改 - 未显示。)
- 在不使用这些设置的情况下再次将
JToken
层次结构序列化为最终字符串(通过json.ToString()
)。
当您这样做时,在第 1 步中选择的日期格式设置会丢失。
要解决这个问题,您需要在每次从 JSON 字符串表示序列化或向 JSON 字符串表示序列化时应用设置,因为,如 this documentation page 中所述,JSON 没有日期的 "official" 格式。正因为如此,Json.NET 应用启发式方法来识别和格式化日期,每当它从 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()
(or 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"
原因 DateTime
properties to be serialized in DateTimeOffset
format you might need to use a custom converter。