6

DateTime オブジェクトを適切にシリアル化し (BinaryWriter を使用するなど)、その完全な状態を保持するにはどうすればよいですか?

日時は内部の長整数でのみ表され、この整数はTicksDateTime のプロパティとしてアクセスできるという印象を受けました。ただし、実装を見ると、Ticks プロパティは実際には、呼び出された ulong に格納されている実際の内部データのサブセットを返します。dateData

Ticks (InternalTicks を取得するだけ) は次のように実装されます。

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

私が見る限り、これは、Ticksプロパティによって明らかにされていない情報が dateData に含まれている可能性があることを意味します。

見知らぬ人ですが、DateTime の BinaryFormatter Serialization は GetObjectData() でこれを行います。

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

これにより、ストリームに2 つのlongが出力され、そのうちの 1 つは他のものから簡単に回復できます。

内部状態を失うリスクなしに DateTime をシリアル化するにはどうすればよいですか (もちろん、8 バイトだけでリフレクションなしで行うことが望ましい)。ulongに直接キャスト(安全でない)できるのではないかと考えていますか?

それとも、理由もなく心配していTicksますか?プロパティは実際に必要なすべての状態をエンコードしますか?

4

2 に答える 2

12

心配すべき情報が 2 つあります。

  • ティックス
  • 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 の内部に関する知識を利用しており、理論的には将来変更される可能性があり、この種のシリアル化が壊れる可能性があります。


編集

現地時間の調整に関係する問題がいくつかあります。

したがって、上記のすべてをいじる代わりに、ローカル時間の調整に関する警告を条件として、long としてシリアル化できるDateTime.ToBinary()およびDateTime.FromBinary()メソッドを確認することをお勧めします。これらの警告は、上記の MSDN リンクに完全に記載されています。

于 2013-04-10T07:44:26.227 に答える
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);
    }
}

編集

バイナリフォーマッタなし

//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 
于 2013-04-10T08:07:32.813 に答える