将DateTime序列化为二进制

And*_*ren 6 .net c# serialization

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

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

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

public long InternalTicks
{
    get { return (long) this.dateData & 4611686018427387903L; }
}
Run Code Online (Sandbox Code Playgroud)

据我所知,这意味着dateData可能包含Ticks属性未透露的信息.

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

info.AddValue("ticks", this.InternalTicks);
info.AddValue("dateData", this.dateData);
Run Code Online (Sandbox Code Playgroud)

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

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

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

Mat*_*son 11

需要担心的有两条信息:

  • 蜱虫
  • DateTimeKind

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

this.dateData = (ulong) (ticks | (((long) kind) << 62));
Run Code Online (Sandbox Code Playgroud)

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

dateData 编码的所有数据,所以它是一件奇怪的事,该串行器可同时存储这 Ticks!

所以你能做的就是:

ulong dataToSerialise = (ulong) (date.Ticks | ((long) date.Kind) << 62);
Run Code Online (Sandbox Code Playgroud)

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

long ticks = (long)(deserialisedData & 0x3FFFFFFFFFFFFFFF);
DateTimeKind kind = (DateTimeKind)(deserialisedData >> 62);
DateTime date = new DateTime(ticks, kind);
Run Code Online (Sandbox Code Playgroud)

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


编辑

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

所以我要建议的是,而不是摆弄所有上述的,你看DateTime.ToBinary()DateTime.FromBinary()哪个方法让你序列化为一个长期的,应遵守与本地时间调整的注意事项.这些警告在上面的MSDN链接中有完整记录.


Jac*_*nan 5

我已经通过序列化在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);
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑

没有二进制格式

//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 
Run Code Online (Sandbox Code Playgroud)