Serialize DateTime as binary

How to serialize a DateTime object (for example, using BinaryWriter) and save its full state?

I had the impression that the time of the date was represented only by an internal long integer and that this integer was available as the Ticks property for DateTime. However, looking at the implementation, the Ticks property actually returns a subset of the actual internal data that is stored in ulong called dateData

Ticks (which just receives InternalTicks) is implemented as follows:

 public long InternalTicks { get { return (long) this.dateData & 4611686018427387903L; } } 

As far as I can see, this means that dateData may contain information that is not displayed using the Ticks property.

Even stranger, BinaryFormatter Serializing DateTime does this in GetObjectData ():

 info.AddValue("ticks", this.InternalTicks); info.AddValue("dateData", this.dateData); 

This will give two threads in a thread, where one of them will be easily restored from the other!

How can I serialize my DateTime without risk of losing any internal state (preferably, of course, in just 8 bytes and without reflection). I think maybe it can be thrown (insecurely), right in the oolong?

Or am I worried for no reason, will the Ticks property encode all the necessary state?

+6
source share
2 answers

You need to worry about two details of the information:

  • The ticks
  • DateTimeKind

Inside, they are both encoded into the same long DateData:

 this.dateData = (ulong) (ticks | (((long) kind) << 62)); 

Thus, the Ticks property will not encode the entire state. It will not receive DateTimeKind information.

dateData encodes all the data, so it is interesting that the serializer saves both Ticks !

So what you can do is the following:

 ulong dataToSerialise = (ulong) (date.Ticks | ((long) date.Kind) << 62); 

And with deserialization you can do this:

 long ticks = (long)(deserialisedData & 0x3FFFFFFFFFFFFFFF); DateTimeKind kind = (DateTimeKind)(deserialisedData >> 62); DateTime date = new DateTime(ticks, kind); 

This uses knowledge of the DateTime internals, and it could theoretically change in the future, which could break such serialization.


EDIT

There are some problems with local time settings.

So, I'm going to assume that instead of messing around with all of the above, you are looking at DateTime.ToBinary() and DateTime.FromBinary() , which will allow you to serialize as long, given the caveats associated with setting the time locally. These disclaimers are fully documented in the MSDN links above.

+8
source

I did this with serialization for passing dates in TCP sockets

here is code that you can serialize with 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 binary formatting

 //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 
+5
source

All Articles