为什么Json.NET的DeserializeObject方法会将时区更改为本地时间?

54

我正在使用json.net将一个DateTimeOffset进行反序列化,但它却忽略了指定的时区并将日期时间转换为本地偏移量。例如,给定:

var content = @"{""startDateTime"":""2012-07-19T14:30:00+09:30""}";

使用以下方式进行反序列化:

var jsonSerializerSettings = new JsonSerializerSettings() { DateFormatHandling = DateFormatHandling.IsoDateFormat, DateParseHandling = DateParseHandling.DateTimeOffset, DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind };
var obj = JsonConvert.DeserializeObject(content, jsonSerializerSettings);

obj对象包含一个属性,该属性包含一个DateTimeOffset,但其值将是2012-07-19T15:30:00+10:30,即已转换为本地时区,而不是保留原始时区。

是否有办法按预期解析值,使得生成的DateTimeOffset属性与提供的值匹配?


4
有趣的是日期/时间实际上是正确的,+9:30时区的14:30必须是+10:30时区的15:30。 - Steen Tøttrup
不确定这里是否有任何关系,但似乎 WCF 序列化/反序列化默认也会执行此操作。也许相同的解决方案可以帮助你:http://daveonsoftware.blogspot.com/2008/07/wcf-datetime-field-adjusted.html - Jesse C. Slicer
对于其他人的提示。有时最好使用 DateParseHandling.None 将日期输出为 string 并自行解析。 - andrew.fox
9个回答

17

我不知道这个错误是否已经被修复。 - Peter Ritchie
@PeterRitchie,您解决了这个问题吗?我正在使用8.0.3版本,但仍然遇到相同的问题。 - Jasmeet
@JasmeetSingh 在 Newtonsoft 网站上显示为已修复。 - Peter Ritchie
@PeterRitchie,是的,我看到了。我的情况是有两个API封装在一起,所以我必须在封装的那个上进行设置更改。谢谢。 - Jasmeet

16
尝试使用这个:
microsoftDateFormatSettings = new JsonSerializerSettings
{
    DateFormatHandling = DateFormatHandling.MicrosoftDateFormat,
    DateTimeZoneHandling = DateTimeZoneHandling.Local
};
var items = JsonConvert.DeserializeObject<List<lstObject>>(jsonString, microsoftDateFormatSettings);

我不知道它是否适用于所有情况,但对我来说是有效的。您可以尝试其他的 DateTimeZoneHandling 值,或在Google上搜索更多选项。

未能工作 - 异常 - hamaronooo
无法工作,当解析时仍会重新计算为本地时间并添加本地的UTC偏移量。 - jasmin

16
如果你正在使用.NET WebApi,你可以将以下内容添加到WebApiConfig.cs文件中,在整个应用程序中全局处理此问题。
config.Formatters.JsonFormatter.SerializerSettings.DateTimeZoneHandling = 
    Newtonsoft.Json.DateTimeZoneHandling.Local;

这将特别告诉JsonFormatter在序列化和反序列化日期时包含并理解本地时区信息。


11

我不确定你使用的是哪个版本,因为在某个时候我们曾经遇到过同样的问题,然后更新解决了它...

你的代码对我来说也运行错误,但是如果我创建一个类似于

public class A
{
    public DateTimeOffset startDateTime;
}

并打电话

var obj = JsonConvert.DeserializeObject<A>(content, jsonSerializerSettings);

一切都按照预期运作。是的,这肯定是一个缺陷,是的,我不知道如何精确地获得您想要的结果,但可能会对其他人有所帮助。


8

这对我有效,时区被保留

var jss = new JsonSerializerSettings
    {
         DateFormatHandling = DateFormatHandling.IsoDateFormat,
         DateTimeZoneHandling = DateTimeZoneHandling.Local, 
         DateParseHandling = DateParseHandling.DateTimeOffset
    };
var responseObj = JsonConvert.DeserializeObject<dynamic>(body, jss);
return responseObj.Select(s => new {
                    id = s["id"].Value<int>(),
                    date = s["date"].Value<DateTimeOffset>().DateTime,
                });

一个 JSON 主体大致如下:
[
    {
        "id": 211,
        "date": "2017-10-22T12:00:00+03:00",
        "status": 1
    },
    {
        "id": 212,
        "date": "2017-10-28T12:00:00+03:00",
        "status": 1
    }
]

确认这个完美地运作了,我刚刚把所有的DateTime都换成了.NET Core的DateTimeOffset,它完美地工作了。这个答案应该排得更靠前! - Mike Upjohn

1
作为一种简单的方法,您可以将 Date 转换为Ticks 进行序列化,然后将其从 Ticks 转换回 Date 进行反序列化:

序列化:

DateTime date = new DateTime();
ticks = date.Ticks

反序列化

Datetime = new Datetime(ticks);

1

要使用正确的本地日期(Local Date)和自定义的JsonConverter,请执行以下操作:

var obj = JsonConvert.DeserializeObject(json, type, new JsonSerializerSettings {
    DateFormatHandling = DateFormatHandling.MicrosoftDateFormat,
    DateTimeZoneHandling = DateTimeZoneHandling.Local,
    Converters = new JsonConverter[] { new MY_CUSTOM_CONVERTER() }
});

我在互联网上努力搜索将它们组合在一起的方法,最终发现JsonConverter可以输入到JsonSerializerSettings中。

0

要在序列化器中使用这些设置,请输入:

var serializerSettings = new JsonSerializerSettings
            {
                DateFormatHandling = DateFormatHandling.MicrosoftDateFormat,
                DateTimeZoneHandling = DateTimeZoneHandling.Local
            };
            var serializer = JsonSerializer.Create(serializerSettings);

0
这是唯一对我有效的方法(与其他提供的答案不同,它们都无效)。关键在于使用DateParseHandling.None。
以前,JsonConvert.DeserializeObject会将英国日期转换为美国日期,即使是连字符形式。例如,将2023-06-08转换为2023-08-06。
var jsonSerializerSettings = new JsonSerializerSettings
        {
            DateFormatHandling = DateFormatHandling.IsoDateFormat,
            DateTimeZoneHandling = DateTimeZoneHandling.Local,
            DateParseHandling = DateParseHandling.None
        };

然后:
JsonConvert.DeserializeObject<*class*>(response.Content.ReadAsStringAsync().Result, jsonSerializerSettings);

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