1

I have a Java program that reads each value from a database and converts it to a byte array. I am currently trying to write an equivalent program in C#. However, I'm having difficulties with DateTimes. The Java code and the C# code produce different byte values.

Here is the Java code:

ResultSet rs = stmt.executeQuery("select * from " + query);
while (rs.next())
{
    for (int j = 1; j <= rs.getMetaData().getColumnCount(); j++)
    {
        byte[] b = rs.getBytes(j);
        if (!rs.wasNull() && b != null)
        {
            for(int i = 0; i < b.length; i++)
                System.out.print(b[i] + " ");
        }
    }
}

Output for the DateTime 2/19/2016 3:12:21 PM:

-71 -3 65 70 116 -74 -28 64

Here is the C# code:

OleDbCommand cmd = new OleDbCommand("select * from " + name, conn);
OleDbDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
    for (int i = 0; i < rdr.FieldCount; i++)
    {
        if (rdr[i] != DBNull.Value && rdr[i] is DateTime)
        {
            DateTime date = (DateTime)rdr[i];
            byte[] b = BitConverter.GetBytes((long)date.Ticks);
            foreach (byte bt in b)
                Console.Write(unchecked((sbyte) bt) + " ");
        }
    }
}

Output for the DateTime 2/19/2016 3:12:21 PM:

-128 -72 98 16 63 57 -45 8

I am not sure how to get these to match. According to the Java documentation for ResultSet's getBytes(int columnIndex) method, "the bytes represent the raw values returned from the driver". So it seems that, unlike the standard C# protocol, it is NOT using the ticks value in order to produce the bytes. This becomes apparent when attempting to translate the byte array back into a DateTime. Converting -71 -3 65 70 116 -74 -28 64 into a long gives you 4676062923628608953. But that value exceeds the maximum tick value for a DateTime, so it cannot be converted into a valid DateTime.

So how does Java end up with those particular byte values then?

I need a way of converting DateTime to byte[ ] in C# that will ALWAYS have the same behavior as Java's getBytes(int columnIndex) method. I cannot modify the Java code. The C# output must match the Java output. Is this possible?

jmwilkes
  • 19
  • 3
  • Can you share the Java code that stores the dates in the database? (Or is it C# code that stores the dates in the database?) – adv12 Apr 29 '16 at 20:06
  • 1
    Little-endian and big-endian confusion? – bcsb1001 Apr 29 '16 at 20:08
  • 3
    Java uses the milliseconds since January 1, 1970. C# uses `Ticks` - one ten millionth of a second, and counts them starting from January 1, 0001. – Scott Hannen Apr 29 '16 at 20:14
  • `getBytes()` is not defined for non-binary data, e.g. it may return driver-specific data. To get a date value, use `getDate()` or `getTimestamp()`, both of which provides a `long getTime()` method for retrieving the number of milliseconds since January 1, 1970, 00:00:00 GMT. You can then convert that to whatever byte sequence you want. – Andreas Apr 29 '16 at 20:36
  • @Andreas I can't modify the Java code though, only the C#. Which is a problem. Obviously the value I got from getBytes() does not represent the number of milliseconds since Jan 1st 1970. 4676062923628608953 milliseconds is 148 million years. So it sounds like I can't get an accurate number of milliseconds without using getDate() or getTimestamp()? – jmwilkes Apr 29 '16 at 20:57

1 Answers1

0

getBytes() is not defined for non-binary data, e.g. it may return driver-specific data.

The bytes represent the raw values returned by the driver.

It would seem that the particular database / JDBC driver you are using is sending the value as a double.

-71 -3 65 70 116 -74 -28 64 is actually b9 fd 41 46 74 b6 e4 40 in hex, which is the double value 42419.633576388886 in Little-Endian order.

byte[] b = { -71, -3, 65, 70, 116, -74, -28, 64 };
System.out.println(ByteBuffer.wrap(b).order(ByteOrder.LITTLE_ENDIAN).getDouble());
42419.633576388886

If you paste that into Excel and format it as m/d/yyyy h:mm:ss AM/PM, you get 2/19/2016 3:12:21 PM.

See here for how to convert in C#.

Community
  • 1
  • 1
Andreas
  • 154,647
  • 11
  • 152
  • 247
  • You are a lifesaver. Changed my C# code to this and it worked like a charm: `byte[] b = BitConverter.GetBytes(date.ToOADate());` Thank you for your help! – jmwilkes Apr 29 '16 at 22:07