protobuf-net does not deserialize DateTime.Kind correctly

protobuf c#
protobuf-net core

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.


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.

c#, 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� The DefaultValues behavior (not just in protobuf-net - in System.ComponentModel generally, protobuf-net does not deserialize DateTime.Kind correctly. 9.


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.

Fix DateTime Serialization bug where DateTimeKind was not , Fix DateTime Serialization bug where DateTimeKind was not serialized/des # 82. Open. ghost wants to merge 8 commits into protobuf-net:master it seemed like this was the change that most concerned you, is that correct? "The protobuf -net library must be able to deserialize protobuf strings serialized� protobuf-net does not deserialize DateTime.Kind correctly. 26. Does protobuf-net have built-in compression for serialization? 3. Protobuf-Net fails on Monodroid with


Another solution is to change kind property for DTO and always set it to UTC. This may not be acceptable for all the application, but works for me

class DateTimeWrapper 
{
    private DateTime _date;

    public DateTime Date 
    {
        get { return _date; }
        set { _date = new DateTime(value.Ticks, DateTimeKind.Utc);}
    }
}
Update

After using protobuf for more than a year and integrating C#, Java, Python and Scala I came to conclusion that one should use a long representation for the DateTime. For example using UNIX time. It's painful to translate C# DateTime protobuf object to other languages DateTime. However, something as simple as long is understood by all.

Protobuf-net Is Broken Around DateTime, Kind when deserializing which can mess with your DateTime values. Protobuf- net is Marc Gravell's port of Protocol Buffers for the . that count to a DateTime representing the Epoch-Time resulting in the correct DateTime value. ToString( "HH:mm:ss K")); // "11:00:00" (no Z means unspecified) Console. The issue turned out to be due to existence of [MyConsoleApp].vshost.exe which apparently is a special version of the executable to aid debugging which I thought would be re-generated after a Rebuild (clearly not) so the solution was to manually delete it and now everything works just fine :-)


Here's an implementation for a workaround. Let me know if you can find a better solution. Thanks!

[ProtoContract(SkipConstructor = true)]
public class ProtoDateTime
{
    [ProtoIgnore]
    private DateTime? _val;

    [ProtoIgnore]
    private DateTime Value
    {
        get
        {
            if (_val != null)
            {
                return _val.Value;
            }
            lock (this)
            {
                if (_val != null)
                {
                    return _val.Value;
                }
                _val = new DateTime(DateTimeWithoutKind.Ticks, Kind);
            }
            return _val.Value;
        }
        set
        {
            lock (this)
            {
                _val = value;
                Kind = value.Kind;
                DateTimeWithoutKind = value;
            }
        }
    }

    [ProtoMember(1)]
    private DateTimeKind Kind { get; set; }
    [ProtoMember(2)]
    private DateTime DateTimeWithoutKind { get; set; }


    public static DateTime getValue(ref ProtoDateTime wrapper)
    {
        if (wrapper == null)
        {
            wrapper = new ProtoDateTime();
        }
        return wrapper.Value;
    }

    public static DateTime? getValueNullable(ref ProtoDateTime wrapper)
    {
        if (wrapper == null)
        {
            return null;
        }
        return wrapper.Value;

    }

    public static void setValue(out ProtoDateTime wrapper, DateTime value)
    {
        wrapper = new ProtoDateTime { Value = value };
    }

    public static void setValue(out ProtoDateTime wrapper, DateTime? newVal)
    {
        wrapper = newVal.HasValue ? new ProtoDateTime { Value = newVal.Value } : null;
    }
}

Usage:

[ProtoContract(SkipConstructor = true)]
public class MyClass
{
    [ProtoMember(3)]
    [XmlIgnore]
    private ProtoDateTime _timestampWrapper { get; set; }
    [ProtoIgnore]
    public DateTime Timestamp
    {
        get
        {
            return ProtoDateTime.getValue(ref _timestampWrapper);
        }
        set
        {
            return ProtoDateTime.setValue(out _timestampWrapper, value);
        }
    }

    [ProtoMember(4)]
    [XmlIgnore]
    private ProtoDateTime _nullableTimestampWrapper { get; set; }
    [ProtoIgnore]
    public DateTime? NullableTimestamp
    {
        get
        {
            return ProtoDateTime.getValueNullable(ref _nullableTimestampWrapper);
        }
        set
        {
            return ProtoDateTime.setValue(out _nullableTimestampWrapper, value);
        }
    }

}

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 are ok but the DateTime.Kind property is� I've written a unit test to capture the problem that I'm running into: the member field is not set when either serializing or deserializing (to/from a byte[]) with protobuf-net. This test fails in the final Assert when validating that the deserialized Version is properly set. It is always set to null instead of the proper "someVersion".


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.

protobuf-net - Google Code Archive, 146, New, DateTime Kind changing during serialization/deserialization round trip EndSubItem does not correctly end byte sequence for length Type-Defect� Deserialize unknown type with protobuf-net. 28. protobuf-net: Serializing an empty List. 522. protobuf-net does not deserialize DateTime.Kind correctly. 6.


如何通过ProtoBuf-net, protobuf-net by mgravell - Protocol Buffers library for idiomatic .NET. DateTime Serialization bug where DateTimeKind was not serialized/des. Kind correctly; Protobuf-net won't deserialize data from Protobuf.js; How do I� ProtoBuf.net Base class properties is not included when serializing derived class. Serialize inherited classes using protobuf-net. My apologies but I did not really understand the answers. I am looking for a faster more compact binary serializer and ProtoBuf looks like it might be the answer.


protobuf-net by mgravell, NET Core SignalR. Using camelCased names won't properly bind to the C# class. Kind is not preserved when serializing/deserializing If you're working with DateTime values in local time, we recommend converting to� Deserializing a string to a string should not arbitrarily change the string. That really sounds like a bug to me, possibly a design bug. I'm not expecting breaking changes to be introduced to fix this, of course; I'm just interested in hearing the auhor's opinion on this. We found a workaround and that's good enough for us right now.


Use MessagePack Hub Protocol in SignalR for ASP.NET Core , MessagePack for C# (.NET, .NET Core, Unity, Xamarin). NuGet Releases Nil is the built-in type representing null/void in MessagePack for C#. Object Serialization. MessagePack for C# can serialize your own public class or struct types. empty collection correctly, because protobuf has no null representation ( see this SO� Since protobuf-net targets idiomatic .NET types that would already serialize just fine with either of these, it seems to me of very little benefit to spend a large amount of time writing JSON support directly for protobuf-net. As such, protobuf-net still does not support this. If there is a genuine need for this, the first thing I would do