Question

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.

  • Windows 64 bit (little endian) hex value FF03D2315FE1C701 should converts to = Sat, 18 August 2007 06:15:37 UTC
  • Windows 64 bit OLE hex value FBE8DF975D3FE340 should converts to = Sun, 02 December 2007 22:11:42 UTC
  • Unix 32 bit (big endian) hex value 46C3B400 should converts to = Thu, 16 August 2007 02:18:40 UTC
  • Apple Mac Absolute hex value 219216022 should converts to = Thu, 13 December 2007 05:20:22 UTC
  • HFS 32 bit (little endian) hex value CD4E55C3 should converts to = Mon, 05 November 2007 22:50:53 Local

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);
Was it helpful?

Solution

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}

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top