如何正确序列化DateTime对象(例如使用BinaryWriter)并保留其完整状态?
我的印象是日期时间仅由内部长整数表示,并且该整数可以作为DateTime的Ticks
属性访问。但是,查看实现,Ticks属性实际上返回真实内部数据的一个子集,该子集存储在名为dateData
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个字节,没有反射)。我想也许它可以被铸造(不安全),直接到一个ulong?
或者我无缘无故担心,Ticks
属性是否会实际编码所有必要的状态?
答案 0 :(得分:11)
需要担心两条信息:
在内部这些都被编码成一个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()
方法作为一个长期,受制于与当地时间调整有关的警告。上面的MSDN链接中详细记录了这些警告。
答案 1 :(得分: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);
}
}
修改强>
没有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