将DateTime序列化为二进制

如何正确序列化DateTime对象(例如使用BinaryWriter),并保持其完整状态?

我的印象是日期时间仅由内部长整数表示,并且该整数可以作为DateTime的Ticks属性访问。 但是,查看实现,Ticks属性实际上返回真实内部数据的子集,该子集存储在名为dateData的ulong中

Ticks(刚刚获得InternalTicks)实现如下:

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

据我所知,这意味着dateData可能包含Ticks属性未显示的信息。

更奇怪的是,DateTime的BinaryFormatter序列化在GetObjectData()中执行此操作:

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

这将在流中输出两个长点,其中一个很容易从另一个中恢复!

如何序列化我的DateTime而不会丢失任何内部状态的风险(当然最好只有8个字节,没有reflection)。 我想也许它可以被铸造(不安全),直接到ulong?

或者我无缘无故担心, Ticks属性是否会实际编码所有必要的状态?

需要担心的有两条信息:

  • 蜱虫
  • DateTimeKind

在内部这些都被编码成一个long,dateData就像这样:

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

因此Ticks属性不会编码所有状态。 它将缺少DateTimeKind信息。

dateData 会对所有数据进行编码,因此序列化程序存储 Ticks都是一件奇怪的事情!

所以你能做的就是:

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

反序列化时,您可以这样做:

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

这确实利用了关于DateTime内部的知识,它在理论上可以在将来改变,这可能会破坏这种序列化。


编辑

当地时间调整有一些问题。

所以我建议不要乱搞上述所有内容,而是查看DateTime.ToBinary()DateTime.FromBinary()方法,这些方法允许您序列化为long,但需遵守与之相关的警告。当地时间调整。 上面的MSDN链接中详细记录了这些警告。

我已经通过序列化在TCP套接字中传输日期

这里是代码,您可以序列化这样的任何对象

 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); } } 

编辑

没有二进制格式

 //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