Сериализовать DateTime как двоичный
Как правильно сериализовать объект DateTime (например, с помощью BinaryWriter) и сохранить его полное состояние?
у меня сложилось впечатление, что время даты представлено только внутренним длинным целым числом, и что это целое число доступно как Ticks
свойство DateTime. Однако, глядя на реализацию, свойство Ticks фактически возвращает подмножество реальных внутренних данных, которое хранится в ulong под названием dateData
галочки (которые just gets InternalTicks) реализуется следующим образом:
public long InternalTicks
{
get { return (long) this.dateData & 4611686018427387903L; }
}
насколько я вижу, это означает, что dateData может содержать информацию, которая не раскрывается Ticks
собственность.
еще более странно, что сериализация BinaryFormatter DateTime делает это в GetObjectData ():
info.AddValue("ticks", this.InternalTicks);
info.AddValue("dateData", this.dateData);
это выведет два долго в потоке, где один из них будет легко recovererd от другого!
как сериализовать DateTime без риска потерять какое-либо внутреннее состояние (желательно, конечно, всего за 8 байт и без отражения). Я думаю, может быть, его можно бросить (небезопасно), прямо на улонг?
или я беспокоюсь без причины, будет Ticks
свойство фактически кодирует все необходимое состояние?
2 ответов
есть две части информации, чтобы беспокоиться о:
- Галочки
- DateTimeKind
внутренне они оба закодированы в один длинный, dateData так:
this.dateData = (ulong) (ticks | (((long) kind) << 62));
так Ticks
недвижимость не кодировать все государство. В нем будет отсутствовать информация DateTimeKind.
The 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, и это теоретически может измениться в будущем, что может нарушить этот вид сериализации.
редактировать
есть некоторые gotchas делать с местным временем регулировка.
поэтому я собираюсь предложить, чтобы вместо того, чтобы возиться со всем вышеперечисленным, вы посмотрели на DateTime.ToBinary()
и DateTime.FromBinary()
методы будет позволяет сериализовать как длинный, с учетом предостережений, связанных с корректировкой местного времени. Эти предостережения полностью документированы в ссылках 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);
}
}
редактировать
без 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