0

We have a method to convert the date in milliseconds in long format to byte array so that we can send it to network.

We were using below method to convert from long to byte in java. But our java was 32 bit, and thus we were converting the long to array of 4 bytes.

   private static byte[] longToBytes(final long value) {
        
        final byte[] bytes = new byte[4];

        for (int i = 0; i < bytes.length; ++i) {
            final int offset = (bytes.length - i - 1) * 8;
            bytes[i] = (byte) (((value & (0xff << offset)) >>> offset));
        }
        return bytes;
    }

But now since the java got updated to 64 bit, we are getting warning for this conversion from coverity. That the expression is evaluated using 32 bit airthmatic and then used in type long. So information loss could happen.

Now, I dont want to use byte array with 8 bytes bcoz I dont know what it will do to our underlying protocol and how it is expecting the byte array size. But I wanted to know in which case can it cause issue. Can date be of 64 bits? Any thoughts on the possible concerns in using this code?

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
Onki
  • 1,879
  • 6
  • 38
  • 58
  • 1
    Long has always been 64 bits in Java, which can only be stored in 8 bytes. It has been this way since 1994, and it has nothing to do with a 32 or 64 bit JVM – Erwin Bolwidt Jul 12 '20 at 10:25
  • You probably won’t want to care, but for other readers: other and perhaps better ways to do the conversion are in [Java integer to byte array](https://stackoverflow.com/questions/2183240/java-integer-to-byte-array). – Ole V.V. Jul 12 '20 at 13:45
  • @OleV.V. in millliseconds we are representing the date – Onki Jul 12 '20 at 14:33

2 Answers2

1

The long type has been 64 bits since the first version of java came out 25+ years ago. Same for Date: it has always used a 64 bit value to count the milliseconds since the Unix epoch Jan 1 1970. The target architecture of the JVM (32/64 bit) plays no role here.

Your new code quality tool is warning that combining int and long types in bit arithmetic may have unexpected outcomes. I'm guessing it would prefer you wrote the code as:

final long offset = (bytes.length - i - 1L) * 8L;
bytes[i] = (byte) (((value & (0xffL << offset)) >>> offset));

I'm concerned that this code uses only the lowest 4 bytes of the long date value. If you're using millisecond timestamps, you are losing information in this conversion. For example, the current timestamp (in hex) is 17342e07b15 and you're sending out 42e07b15 as the output.

Joni
  • 108,737
  • 14
  • 143
  • 193
1

in millliseconds we are representing the date

Which numbers you can represent in 4 bytes — 32 bits — depends on whether the receiver interprets them as a signed or an unsigned number.

  • A signed 32 bit integer goes from -2147483648 to 2147483647. If these numbers are milliseconds since the epoch, you can represent dates and times from 1969-12-07T03:28:36.352Z to 1970-01-25T20:31:23.647Z. That’s pretty narrow range for most applications. It sounds to me like you are having a very real problem, and I wonder how it could go unnoticed.
  • If the number is unsigned, dates and times can go up to 1970-02-19T17:02:47.295Z. It’s still a bit over 50 years ago.

For comparison the time now is represented as 1_594_564_976_456 milliseconds since the epoch. It takes 41 bits to represent this number as an unsigned number, or 42 bits if signed (did they say the answer was 42? ;-) So at least 6 bytes.

And you are correct, it probably won’t solve it to send 6 or 8 bytes when the receiver expects 4. A solution will take more than that.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161