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

标签 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. 使用特定的 DateTime 相关序列化设置将 Class2 的实例序列化为 JSON 字符串。
  2. 反序列化为 JToken 层次结构而不使用这些设置
  3. (对层次结构进行其他修改 - 未显示。)
  4. 在不使用这些设置的情况下再次将 JToken 层次结构序列化为最终字符串(通过 json.ToString())。

当您这样做时,在第 1 步中选择的日期格式设置会丢失。

要解决此问题,您需要在每次从 JSON 字符串表示序列化或向其序列化时应用设置,因为,如 this documentation page 中所述。 , JSON 没有日期的“官方”格式。因此,每当 Json.NET 与 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);

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

关于c# - Json.Net 在序列化时弄乱了 DateTimeOffset 的时区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44426207/

相关文章:

c# - 最小化 FormClose 防止计算机关机

c# - 使用 LINQ 从具有特定名称的数组中获取游戏对象

c# - WCF 服务无法返回 1/1/0001 DateTime

sql - 可序列化事务隔离锁

c++ - 如何在C++中记录用户定义的POD结构

c# - 从 Javascript 中的序列化数据获取特定值

c# - 如何在 Windows 8.1 应用程序 xaml 中的 MenuFlyoutItem 内添加 StackPanel

c# - 在 Xamarin Android 中访问 UI 线程

python - 获取周开始日不同于周一的周数 - Python

ruby-on-rails - 将日期时间拆分为两个单独的表单字段 (RAILS)