D P.
D P.

Reputation: 1079

Decode date/time hexadecimal values found embedded within binary files

I am trying to write a C# program similar to the one on this website: http://www.digital-detective.co.uk/freetools/decode.asp

Can you please tell me how I can convert the hex numbers listed in the following bulletins to Date/Time values.

I was trying to use the following code to do that, but it doesn't return the correct result:

double decValue = int.Parse("A2C3B446", System.Globalization.NumberStyles.HexNumber);
System.DateTime dtDateTime = new DateTime(2013, 1, 1, 0, 0, 0, 0);
dtDateTime = dtDateTime.AddSeconds(decValue).ToLocalTime();
Console.WriteLine("Decimal Value: " + decValue);
Console.WriteLine(dtDateTime);

Upvotes: 3

Views: 3542

Answers (1)

Hans Passant
Hans Passant

Reputation: 942000

You'll first want a utility method that reads bytes from a stream and handles the endian-ness. That could look like:

    public static byte[] ReadBytes(Stream s, int size, bool littleEndian) {
        var bytes = new byte[size];
        var len = s.Read(bytes, 0, size);
        if (len != size) throw new InvalidOperationException("Unexpected end of file");
        if (BitConverter.IsLittleEndian != littleEndian) Array.Reverse(bytes);
        return bytes;
    }

Windows dates are easy, supported by DateTime.FromFileTimeUtc() directly:

    public static DateTime ConvertWindowsDate(byte[] bytes) {
        if (bytes.Length != 8) throw new ArgumentException();
        return DateTime.FromFileTimeUtc(BitConverter.ToInt64(bytes, 0));
    }

Testing it with your value:

    var date1 = DateReaders.ConvertWindowsDate(DateReaders.ReadBytes(
                    new MemoryStream(new byte[]{0xFF,0x03,0xD2,0x31,0x5F,0xE1,0xC7,0x01}), 8, true));

Produces {8/18/2007 6:15:37 AM} as expected.


OLE dates are easy, supported by DateTime.FromOADate() directly:

    public static DateTime ConvertOLEDate(byte[] bytes) {
        if (bytes.Length != 8) throw new ArgumentException();
        return DateTime.FromOADate(BitConverter.ToDouble(bytes, 0));
    }

Testing it with your value:

    var date2 = DateReaders.ConvertOLEDate(DateReaders.ReadBytes(
                    new MemoryStream(new byte[] {0xFB,0xE8,0xDF,0x97,0x5D,0x3F,0xE3,0x40 }), 8, true));

Produces {12/2/2007 10:11:41 PM}


Unix date values are milliseconds from Jan 1st, 1970, 0:00 AM UTC:

    public static DateTime ConvertUnixDate(byte[] bytes) {
        if (bytes.Length != 4) throw new ArgumentException();
        return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(
                  BitConverter.ToUInt32(bytes, 0));
    }

Testing it with your value:

    var date3 = DateReaders.ConvertUnixDate(DateReaders.ReadBytes(
                   new MemoryStream(new byte[] {0x46,0xC3,0xB4,0x00}), 4, false));

Produces {8/16/2007 2:18:40 AM}


Apple Mac absolute time is documented to be CPU dependent and requires conversion on the machine that generated it. The shown value "219216022" is quirky, it appears to decimal instead of hex like all the other ones. I'll follow Baldrick's lead with:

public static DateTime ConvertAppleDate(byte[] bytes) {
    if (bytes.Length != 4) throw new ArgumentException();
    return new DateTime(2001, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(
              BitConverter.ToUInt32(bytes, 0));
}

HFS dates are seconds since Jan 1st, 1904, 0:00 AM. Do note that HFS dates are local time but HFS Plus dates are UTC. I'll assume local since that's the result you documented:

    public static DateTime ConvertHFSDate(byte[] bytes) {
        if (bytes.Length != 4) throw new ArgumentException();
        return new DateTime(1904, 1, 1, 0, 0, 0, DateTimeKind.Local).AddSeconds(
                  BitConverter.ToUInt32(bytes, 0));
    }

Testing it with your value:

    var date5 = DateReaders.ConvertHFSDate(DateReaders.ReadBytes(
                   new MemoryStream(new byte[] {0xCD,0x4E,0x55,0xC3 }), 4, true));

Produces {11/5/2007 10:50:53 PM}

Upvotes: 18

Related Questions