Json.Net反序列化DateTime不一致

5

我在使用Json.Net 6.0.3(我也可以在6.0.6上复制该问题)反序列化日期时间时遇到了问题。代码在Windows 8.1的.Net 4.5中运行,文化为en-GB。

以下是问题的演示:

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

输出结果:

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

日期时间格式因访问 JObject 的方式而异,一个是 MM/DD/YYYY,另一个是 DD/MM/YYYY。为什么会这样呢?
我不需要它们以特定的格式出现:问题在于格式会改变。我有很多旧代码解析自 Json.Net 的日期时间字符串。该代码也将在世界各地的不同计算机上运行,可能使用不同的文化。
有没有办法让 Json.Net 总是以相同的格式返回日期时间?
1个回答

8
问题在于这两行代码执行了不同的操作:
jo["time"]

最终在控制台上打印的是一个实际的DateTime值。正如@JonSkeet指出的,你实际上正在将一个JValue写入控制台- 但是JValue.ToString只是调用了包装值的ToString方法而已,在你的情况下,这是DateTime.ToString()

换句话说:

  • 调用Console.WriteLine并传递JValue实例使用了接受object参数的Console.WriteLine重载。
  • 该重载在JValue上调用.ToString()
  • 然后在基础类型(在您的情况下是DateTime)上调用.ToString()

因此,您将获得当前区域设置中默认格式的日期时间。更具体地说,您将获得当前区域设置中使用“G”格式说明符格式化的DateTime

更有趣的部分是jo.Value<string>("time")这一行。在底层,JSON.NET使用以下方式将基础DateTime转换为字符串:

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

当然,这会产生完全不同的字符串,因为它明确地使用了CultureInfo.InvariantCulture

从中可以得出结论,你最好的选择可能是将日期作为DateTime获取,然后以你想要的精确方式进行格式化,以避免任何歧义:

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

@JonSkeet:嗯,是的,我把它简化了,但是JValueToString方法调用底层值(在这种情况下是DateTime)的ToString方法。 - Andrew Whitaker
1
好的,如果我是你,我会避免过于简化它。基本前提是正确的(这就是为什么我放弃了自己的答案),但在涉及到各种转换时,准确性非常重要。 - Jon Skeet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接