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?
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#.
Related
This question already has answers here:
how to encode and decode emoji in android?
(8 answers)
Closed 2 years ago.
I am making an ASCII Encoder-Decoder. I am encoding the characters into UTF-8. To encode I am using this code:
private String asciiReturn(String inpString){
int codePoint = 0;
StringBuilder str = new StringBuilder();
for (int i = 0; i < inpString.length(); i++){
codePoint = Character.codePointAt(inpString, i);
i += Character.charCount(codePoint) - 1;
str.append(codePoint);
str.append(" ");
}
return str.toString();
}
So by this, I can encode all those emoji characters too.
Like '🤷🏻♂️' for this emoji I am getting "129335 127995 8205 9794 65039". So this is basically the UTF-8 decimal value of the emoji and that's exactly what I want. But my problem is the decoding.
What I want is: (Example)
Input String: "72 117 104 33 129335 127995 8205 9794 65039"
Output String: "Huh!🤷🏻♂️"
Cause:
72 -> 'H'
117 -> 'u'
104 -> 'h'
33 -> '!'
129335 127995 8205 9794 65039 -> '🤷🏻♂️'
Thanks in advance 🙂
Try this.
private String decode(String inpString) {
return Arrays.stream(inpString.split("\\s+"))
.map(s -> Character.toString(Integer.parseInt(s)))
.collect(Collectors.joining());
}
and
String input = "72 117 104 33 129335 127995 8205 9794 65039";
System.out.println(decode(input));
output
Huh!🤷🏻♂️
You can also write your encoding method like this:
static String asciiReturn(String s) {
return s.codePoints()
.mapToObj(Integer::toString)
.collect(Collectors.joining(" "));
}
and
String s = "Huh!🤷🏻♂️";
System.out.println(asciiReturn(s));
output
72 117 104 33 129335 127995 8205 9794 65039
I'm not sure what is causing this exception, and the stack trace isn't being helpful as it states it was caused by an unknown source.
The method below takes two hexadecimal strings, one representing an opcode and one representing an operand, and converts them to binary before concatenating them and adding them to an arraylist. Simple enough. In order to ensure each binary string includes the full 8 bits I'm using a small utility method called hexToBinary, for some reason, when I attempt to use this method to convert my hexadecimal strings it causes the exception.
The opcode and operands, which are taken from the asmLine objects give this input below:
A9 10
90 C6
0A 00
11 FF
38 00
7D FF
81 FF
A1 09
AA 00
20 11
58 00
6C 09
FE 10
All of the above hexadecimal values should be converted to binary. But this is not happening. The strange thing is that when I explicitly state the hexadecimal value to be converted by the utility method, as I do with the line String beginBinary = Utils.hexToBinary("FA"); works completely normally. I just can't understand why this isn't working when I'm using the values pulled from the asmLine objects.
public void constructBinaryOutput()
{
ArrayList<String> binaryOut = new ArrayList<String>();
String beginBinary = Utils.hexToBinary("FA"); //This works normally
String endBinary = Utils.hexToBinary("FF"); //This works normally
String twoByteString = beginBinary.concat(" " + beginBinary);
binaryOut.add(twoByteString);
for(AssemblyLine asmLine : lineObjects)
{
String opcodeHex = asmLine.getOpcodeHEX();
String operandHex = asmLine.getOperandHEX();
System.out.println("Hex opcode/operand: " + opcodeHex + " " + operandHex);
String opcodeBinary = Utils.hexToBinary(opcodeHex); //This causes an exception
String operandBinary = Utils.hexToBinary(operandHex);
System.out.println("Hex opcode " + asmLine.getOpcodeHEX() + " converted into binary " + opcodeBinary);
System.out.println("Hex operand " + asmLine.getOperandHEX() + " converted into binary " + operandBinary);
twoByteString = opcodeBinary.concat(" " + operandBinary);
System.out.println("2 Byte instruction: " + twoByteString);
binaryOut.add(twoByteString);
}
}
Utility method hexToBinary
public static String hexToBinary(String hex)
{
String bin = Integer.toBinaryString(Integer.parseInt(hex,16));
int length = bin.length();
return length == 8 ? bin : "00000000".substring(length - 8) + bin;
}
Just a simple mistake in your util function. It should be:
public static String hexToBinary(String hex) {
String bin = Integer.toBinaryString(Integer.parseInt(hex, 16));
int length = bin.length();
return length == 8 ? bin : "00000000".substring(length) + bin;
}
notice the substring.
HTH,
Gal
This question already has answers here:
BigInteger.toString method is deleting leading 0
(5 answers)
Closed 5 years ago.
I' m writting a password generator for a script in PHP and I want it to be compatible with a class I wrote in Java, so that they can share resources.
PHP code:
public function PasswordGen($password, $rounds) {
for($i = 0; $i < $rounds; $i++) {
$password = substr(base64_encode(md5($password)), 0, 16);
echo $i . " " . $password . PHP_EOL; // debugging //
}
return $password;
}
Java code:
public static String PasswordGen(String password, int rounds) {
try {
for(int i = 0; i < rounds; i++) {
byte[] md5 = MessageDigest.getInstance("MD5").digest(password.getBytes("UTF-8"));
String md5h = (new BigInteger(1, md5)).toString(16);
password = Base64.getEncoder().encodeToString(md5h.getBytes()).substring(0, 16);
System.out.println(Integer.toString(i) + " " + password); // debugging //
}
} catch(Exception ex) {
ex.printStackTrace();
return null;
}
return password;
}
PHP debug output:
0 MWExZGM5MWM5MDcz
1 NDVkZmMxNWVjNWZi
2 ODY5YzVkODBhNTRh
3 ZGE2OTNiOWMxOWM1
4 OTcxMTY3MzgxMmRk
5 NWNjNDI2N2IzMDlj
6 NGVkYzY0YjVkMWUy
7 MjdhMGU4NjhhNmU3
8 OWY5OGE3ZGZiODZl
9 Y2I1ZjBkNjRmMjkx
10 YTk5NDA1MGI1OWY1
11 YzRmYWE5ZTk0ZDdl
12 NDBiZWZkNmQ5Yjhj
13 MzQyNzcwNGRjMTYw
14 N2U4ZmUxOGMyNWYx
15 MjBjOTZhNGE4ZDQ1
16 MjdmMzkwMzI0NDdj
17 YjM4NDI0YWU0YzUw
18 NDRiNjA1MWUwOGZi
19 MGI1YmIyMDViMGYz
Java debug output:
0 MWExZGM5MWM5MDcz
1 NDVkZmMxNWVjNWZi
2 ODY5YzVkODBhNTRh
3 ZGE2OTNiOWMxOWM1
4 OTcxMTY3MzgxMmRk
5 NWNjNDI2N2IzMDlj
6 NGVkYzY0YjVkMWUy
7 MjdhMGU4NjhhNmU3
8 OWY5OGE3ZGZiODZl
9 Y2I1ZjBkNjRmMjkx
10 YTk5NDA1MGI1OWY1
11 YzRmYWE5ZTk0ZDdl
12 NDBiZWZkNmQ5Yjhj
13 MzQyNzcwNGRjMTYw
14 N2U4ZmUxOGMyNWYx
15 MjBjOTZhNGE4ZDQ1
16 MjdmMzkwMzI0NDdj
17 YjM4NDI0YWU0YzUw
18 NDRiNjA1MWUwOGZi
19 YjViYjIwNWIwZjMy
It works as expected until the 19th loop. Why does it produce different output after that?
In Java, converting a BigDecimal to a hexadecimal String with the toString(int base) method doesn't output leading zeros.
You can discover this by printing the output of the intermediate step (converting the md5 hashcode to an hexadecimal string) - in Java that gives b5bb205b0f32a7bf2a80fc870cbd2b7 while in PHP it gives 0b5bb205b0f32a7bf2a80fc870cbd2b7. It's only a difference of one leading zero, but after applying the base64 encoding, they look very different.
An easier way to get leading zeros is to use the String.format method.
Replace this line:
String md5h = ( new BigInteger(1, md5) ).toString(16);
with this line:
String md5h = String.format("%032x", new BigInteger(1, md5));
and you'll get the same output as with your php code.
I want to take the byte value out of this class so I can parse it, or if it's possible parse it inside and get the 5th and 6th byte value out.
private void broadcastUpdate(final String action,
final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
// This is special handling for the Heart Rate Measurement profile. Data parsing is
// carried out as per profile specifications:
// http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml
if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
for(byte byteChar : data)
stringBuilder.append(String.format("%02X", byteChar));
intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString());
} else {
// For all other profiles, writes the data formatted in HEX.
}
}
sendBroadcast(intent);
}
How this works is that I step on a scale and it sends me these bytes:
00 00 00 00 02 02 00 00 00 00 00 00 00 00 00 00
Which is stored at the variable 'data'. How do I take 'data' out to use in another class?
The weight data is on bytes 5 and 6. If you convert the hex values of bytes 5 and 6, in that example is '0202' it becomes 514 in decimal (51.4kg).
I need to take the bytes data to use in another class to get the kg data. How would I go around doing so?
You can simply get those two bytes and apply below:
int result = ByteBuffer.wrap(bytes).getInt();
If you want more info: HERE1, HERE 2
my hexadecimal string
string s=new String("FF7900002481201132570943440402151302961500080054021E000040FFFFFBFF79000024812011");
i want particular data in string..
my format : 2481201132570943440402151302961500080054021E000040FFFFFBFF790000
it's must starting value in string 24 .
and it's split at end of 62 . values(2481201132570943440402151302961500080054021E000040FFFFFBFF790000=62)
and finally to split the string ?
12 content value in hexadecimal
24 ---> (1)
8120113257 --(5)
094047 ---(3)
040215 ---(3)
13029615 ----- (4)
00 ------- (1)
080054021E -------(5)
000040 ---- (3)
FFFFFBFF -- (4)
79 ---(1)
00 ------(1)
00 ----- (1)
how to solve it in java code?
Thanks
You can parse the String as a series of Strings.
class StringParser {
final StringReader sr;
public StringParser(String text) {
sr = new StringReader(text);
}
public String next(int n) {
char[] chars = new char[n];
sr.read(chars);
return new String(chars);
}
public String nextAsLong(int n) {
return Long.parseInt(next(n));
}
}
StringParser sp = new StringParser("FF7900002481201132570943440402151302961500080054021E000040FFFFFBFF79000024812011");
sp.next(8); // ignored
long first= sp.nextAsLong(2);
long second = sp.nextLong(10);
// etc
You can use
Long.parseLong(string, 16);
Size of content is fixed or floating?
If yes you can use substring and: Long.parseLong("FFFFFBFF", 16);