Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

protobuf-net does not deserialize DateTime.Kind correctly

using protobuf-net.dll Version 1.0.0.280

When I deserialize a DateTime (wrapped in an object), the date/time is ok but the DateTime.Kind property is 'Unspecified'

Consider this test case to serialize/deserialize a DateTime.

[TestMethod]
public void TestDateTimeSerialization()
{
    var obj = new DateTimeWrapper {Date = DateTime.UtcNow};
    obj.Date = DateTime.SpecifyKind(obj.Date, DateTimeKind.Utc);
    var serialized = obj.SerializeProto();
    var deserialized = serialized.DeserializeProto<DateTimeWrapper>();
    Assert.AreEqual(DateTimeKind.Utc, deserialized.Date.Kind);
}

public static byte[] SerializeProto<T>(this T item) where T : class
{
    using (var ms = new MemoryStream())
    {
        Serializer.Serialize(ms, item);
        return ms.ToArray();
    }
}

public static T DeserializeProto<T>(this byte[] raw) where T : class, new()
{
    using (var ms = new MemoryStream(raw))
    {
        return Serializer.Deserialize<T>(ms);
    }
}

The Assert fails, the Kind == Unspecified

Addendum

As a result of protobuf-net not serializing this property (see below) one solution is to assume DateTimeKind is equal to Utc when displaying dates on the client side (only where you know it should be UTC of course):

public static DateTime ToDisplayTime(this DateTime utcDateTime, TimeZoneInfo timezone)
{
    if (utcDateTime.Kind != DateTimeKind.Utc)//may be Unspecified due to serialization
        utcDateTime = DateTime.SpecifyKind(utcDateTime, DateTimeKind.Utc);
    DateTime result = TimeZoneInfo.ConvertTime(utcDateTime, timezone);
    return result;
}

This saves you having to assign to each DateTime property on the receiving side.

like image 596
wal Avatar asked Jul 12 '11 03:07

wal


3 Answers

protobuf.net has to maintain compatibility with the protobuf binary format, which is designed for the Java date/time datatypes. No Kind field in Java -> No Kind support in the protobuf binary format -> Kind not transferred across the network. Or something along those lines.

As it turns out, protobuf.net encodes the Ticks field (only), you'll find the code in BclHelpers.cs.

But feel free to add another field in your protobuf message definition for this value.

like image 73
Ben Voigt Avatar answered Oct 05 '22 01:10

Ben Voigt


As an extension to Ben's answer... strictly speaking, protobuf has no definition of time, so there is nothing to retain compatibility with. I'm tempted to add support for this in v2, but sadly it would add 2 bytes per value. I have yet to think about whether this is acceptable... for example, I could perhaps default to "unspecified" so that only explicitly local or UTC dates have a value.

like image 20
Marc Gravell Avatar answered Oct 05 '22 00:10

Marc Gravell


It might make more sense for protobuf to automatically deserialize the DateTime with the UtcKind, that way if you are using Utc as your base, which I think is best practice anyway, you wont have any issues.

like image 41
Ross Jones Avatar answered Oct 04 '22 23:10

Ross Jones