How do I properly serialize a DateTime object (e.g. using a BinaryWriter), and preserve its complete state?
I was under the impression that a date time was only represented by an internal long integer, and that this integer was accessible as the Ticks
property of the DateTime. However, looking at the implementation, the Ticks property actually returns a subset of the real internal data which is stored in an ulong called dateData
Ticks (which just gets InternalTicks) is implemented like so:
public long InternalTicks
{
get { return (long) this.dateData & 4611686018427387903L; }
}
As far as I can see this means the dateData may contain information that is not revealed by the Ticks
property.
Stranger yet, the BinaryFormatter Serialization of a DateTime does this in GetObjectData():
info.AddValue("ticks", this.InternalTicks);
info.AddValue("dateData", this.dateData);
That will output two longs in the stream, where one of them would be easily recovererd from the other!
How can I serialize my DateTime without risk of losing any of the internal state, (preferably of course in just 8 bytes, and without reflection). I'm thinking maybe it can be cast (unsafe), directly to an ulong?
Or am I worrying for no reason, will the Ticks
property actually encode all the necessary state?
For serializing, you can use the DateTime(Offset). ToString method in your converter write logic. This method allows you to write DateTime and DateTimeOffset values using any of the standard date and time formats, and the custom date and time formats.
In binary serialization, the public and private fields of the object and the name of the class, including the assembly containing the class, are converted to a stream of bytes, which is then written to a data stream. When the object is subsequently deserialized, an exact clone of the original object is created.
There are two pieces of information to worry about:
Internally these are both encoded into a single long, the dateData like so:
this.dateData = (ulong) (ticks | (((long) kind) << 62));
So the Ticks
property will not encode all the state. It will be missing the DateTimeKind information.
The dateData
does encode all the data, so it is a curious thing that the serialiser stores both that and Ticks
!
So what you could do is this:
ulong dataToSerialise = (ulong) (date.Ticks | ((long) date.Kind) << 62);
And when deserializing, you can do this:
long ticks = (long)(deserialisedData & 0x3FFFFFFFFFFFFFFF);
DateTimeKind kind = (DateTimeKind)(deserialisedData >> 62);
DateTime date = new DateTime(ticks, kind);
This does make use of knowledge about the internals of DateTime, and it could theoretically change in the future, which could break this kind of serialisation.
EDIT
There are some gotchas to do with local time adjustment.
So I'm going to suggest that instead of messing about with all of the above, you look at the DateTime.ToBinary()
and DateTime.FromBinary()
methods which will allow you to serialize as a long, subject to the caveats relating to the local time adjustment. These caveats are fully documented in the MSDN links above.
i have done this with serialization for transmitting date in TCP Sockets
here is code you can serialize any object like this
public static byte[] DateToBytes(DateTime _Date)
{
using (System.IO.MemoryStream MS = new System.IO.MemoryStream()) {
BinaryFormatter BF = new BinaryFormatter();
BF.Serialize(MS, _Date);
return MS.GetBuffer();
}
}
public static DateTime BytesToDate(byte[] _Data)
{
using (System.IO.MemoryStream MS = new System.IO.MemoryStream(_Data)) {
MS.Seek(0, SeekOrigin.Begin);
BinaryFormatter BF = new BinaryFormatter();
return (DateTime)BF.Deserialize(MS);
}
}
EDIT
without binaryformatter
//uses 8 byte
DateTime tDate = DateAndTime.Now;
long dtVal = tDate.ToBinary();
//64bit binary
byte[] Bits = BitConverter.GetBytes(tDate.ToBinary());
//your byte output
//reverse
long nVal = BitConverter.ToInt64(Bits, 0);
//get 64bit binary
DateTime nDate = DateTime.FromBinary(nVal);
//convert it to date
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With