JSON.Net BSON 序列化不正确地处理 DateTimeOffset?

标签 json.net bson

我正在尝试使用 JSON.Net 序列化为 BSON,但原始偏移量似乎没有得到遵守。

你能看出我如何努力使这项工作有问题吗?

[Test]
public void SerializeDateTimeOffsetToBson()
{
    var serializer = new Newtonsoft.Json.JsonSerializer {
        TypeNameHandling = TypeNameHandling.Auto,
        DateParseHandling = DateParseHandling.DateTimeOffset,
        DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind
    };

    var negOffset = new DateTimeOffset(2014, 7, 10, 0, 0, 0, new TimeSpan(-5, 0, 0));
    var gmtOffset = new DateTimeOffset(2014, 7, 10, 0, 0, 0, new TimeSpan());
    var posOffset = new DateTimeOffset(2014, 7, 10, 0, 0, 0, new TimeSpan(5, 0, 0));

    var dt = new {
        negOffset = negOffset,
        gmtOffset = gmtOffset,
        posOffset = posOffset
    };

    byte[] serialized;

    using (var ms = new MemoryStream())
    using (var writer = new BsonWriter(ms)) {
        serializer.Serialize(writer, dt);
        writer.Close();
        serialized = ms.ToArray();
    }

    dynamic deserializedDt;

    using (var ms = new MemoryStream(serialized))
    using (var rdr = new BsonReader(ms)) {
        deserializedDt = (dynamic)serializer.Deserialize(rdr);
        rdr.Close();
    }

    Assert.IsTrue(deserializedDt.negOffset == dt.negOffset);
    Assert.IsTrue(deserializedDt.posOffset == dt.posOffset);
    Assert.IsTrue(deserializedDt.gmtOffset == dt.gmtOffset);
}

所有三个断言都会失败。

反序列化后,deserializedDt.negOffset 为 2014 年 7 月 9 日晚上 10 点,偏移量为 -07:00(计算机当前时区),deserializedDt.posOffset 为 7 月 9 日2014 年中午 12 点,偏移量为 -07:00,deserializedDt.gmtOffset 为 2014 年 7 月 9 日下午 5 点,偏移量为 -07:00。

在 .Net 4.0 项目中使用 JSON.Net 8.0.3。

更新--------------------

经过进一步调查,我在 Github 上提出了一个关于此的问题 https://github.com/JamesNK/Newtonsoft.Json/issues/898

最佳答案

BSON 规范不允许存储 DateTime 的偏移量; it stores UTC datetime as an Int64 , 自 Unix 纪元以来的毫秒数。

如果您不想丢失偏移量,您可以创建一个 JsonConverter,它将 DateTime 与偏移量分开,以分别序列化(和反序列化)两者。例如:

public class DateTimeOffsetConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(DateTimeOffset) == objectType;
    }

    public override object ReadJson(
        JsonReader reader, 
        Type objectType, 
        object existingValue, 
        Newtonsoft.Json.JsonSerializer serializer)
    {
        if (reader.TokenType != JsonToken.StartObject)
            return null;

        reader.Read(); // PropertyName "DateTimeInTicks"
        reader.Read(); // Property value
        var ticks = (Int64)reader.Value;

        reader.Read(); // PropertyName "Offset"
        reader.Read(); // Property value
        var offset = TimeSpan.Parse((String)reader.Value);

        // Move forward to JsonToken.EndObject
        reader.Read();

        return new DateTimeOffset(ticks, offset);
    }

    public override void WriteJson(
        JsonWriter writer, 
        object value, 
        Newtonsoft.Json.JsonSerializer serializer)
    {
        var dateTimeOffset = (DateTimeOffset)value;

        var toSerialize = new {
            DateTimeInTicks = dateTimeOffset.DateTime.Ticks,
            Offset = dateTimeOffset.Offset
        };

        serializer.Serialize(writer, toSerialize);
    }
}

然后您可以将它应用到您的类中,如下所示:

public class TestClass
{
    public Int32 TestInt { get; set; }

    [JsonConverter(typeof(DateTimeOffsetConverter))] 
    public DateTimeOffset TestDateTimeOffset { get; set; }

    public String TestString { get; set; }

    [JsonConverter(typeof(DateTimeOffsetConverter))] 
    public DateTimeOffset? TestNullableDateTimeOffset { get; set; }
}

关于JSON.Net BSON 序列化不正确地处理 DateTimeOffset?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36944671/

相关文章:

c# - 在 JSON.NET 中修剪 json 字符串

c# - 序列化为 XML 时如何处理 JSON 键中的空格?

mongodb - 在 MongoDb 上序列化 get-only 属性

rust - Rust-如何检查文件中的EOF?

mongodb - PyMongo 将 BSON 文档插入 MongoDB

java - 在 MongoDB Java 中过滤文档或子文档中的数组

反序列化 JSON 时出现 C# 错误

vb.net - 在 Visual Basic 中使用 json.net 解析嵌套 JSON

json - JsonConvert.DeserializeXmlNode 中的 StackOverflowException

mongodb - mongo bson 对象ID