jmwilkes jmwilkes - 7 months ago 140
Java Question

Difference between C# and Java when converting DateTime to byte array

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?

Answer

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#.

Comments