Convert Long to DateTime from C# Date to Java Date

Tags: , , ,



I’ve been trying to read the binary file with Java, and the binary file is written in C#. And some of those data is contain a DateTime data.

When DateTime data will be written into the file (in binary), it using DateTime.ToBinary(); on C#.

For reading the DateTime data, it will convert first from bytes into long data, using BitConverter.ToInt64(byte[], 0), and then convert it again from long into DateTime data using DateTime.FromBinary(long). (All of those are written in C#).

Let’s say the long data after converting from bytes is = -8586803256090942249, and when convert it into DateTime, it will return = 3/17/2018 5:07:56 PM

Now, I’m trying to read that binary file with Java. And for converting the bytes data into long data, I’m using this code : ByteBuffer.wrap(byte[]).order(ByteOrder.LITTLE_ENDIAN).getLong().

It will return the exact long data value as C# did. But when I try to convert it from long data into DateTime in Java, using Date date = new Date(long), it will return = Sun May 06 19:04:17 WIB 272097407 instead.

Can you help me what is the correct solution for this ? Is there any equivalent for DateTime.FromBinary() from C# in Java ? Or is my code wrong ? All of yours answers is really appreciated.

Answer

In Java:

    long fromBytes = -8586803256090942249L;

    // Mask out kind and ticks
    int kind = Math.toIntExact((fromBytes >> 62) & 0x3);
    long ticks = fromBytes & 0x3FFF_FFFF_FFFF_FFFFL;
    LocalDateTime cSharpEpoch = LocalDate.of(1, Month.JANUARY, 1).atStartOfDay();
    // 100 nanosecond units or 10^-7 seconds
    final int unitsPerSecond = 10_000_000;
    long seconds = ticks / unitsPerSecond;
    long nanos = (ticks % unitsPerSecond) * 100;
    LocalDateTime ldt = cSharpEpoch.plusSeconds(seconds).plusNanos(nanos);

    switch (kind) {
    case 0: // Unspecified
    case 2: // Local time
        System.out.println("Result LocalDateTime: " + ldt);
        break;

    case 1: // UTC
        OffsetDateTime utcDateTime = ldt.atOffset(ZoneOffset.UTC);
        System.out.println("Result OffsetDateTime in UTC: " + utcDateTime);
        break;

    default:
        System.out.println("Not a valid DateTimeKind: " + kind);
        break;
    }

Output:

Result LocalDateTime: 2018-03-17T10:07:56.383355900

Edit: The number is

A 64-bit signed integer that encodes the Kind property in a 2-bit field and the Ticks property in a 62-bit field.

Tetsuya Yamamoto was correct so far as the ticks property denotes number of 100-nanosecond intervals elapsed since 0001/01/01 at start of day (midnight). The kind is either 0 for unspecified, 1 for UTC or 2 for local time. So I am masking the kind and the ticks out separately.

Even though the kind is 2 in your case, which should be for local time, it seems that the time is indeed in UTC. It’s the only way that the time printed could agree with your expected 5:07:56 PM Western Indonesian Time. Maybe the number was generated on a computer with its time zone set to UTC.

To get the time in your time zone:

    ZoneId targetZone = ZoneId.of("Asia/Jakarta");
    ZonedDateTime zdt = ldt.atZone(ZoneOffset.UTC).withZoneSameInstant(targetZone);
    System.out.println("Converted to target time zone: " + zdt);

Converted to target time zone: 2018-03-17T17:07:56.383355900+07:00[Asia/Jakarta]

This agrees with what you said you got on the C# side.

PS Avoid the Date class in Java if you can, it is long outdated and poorly designed and was replaced many years ago now by java.time, the modern Java date and time API (which I am of course using in the above). If you do need a Date for a legacy API that you cannot change or don’t want to change just now, as you already noted in a comment, the conversion is like this:

    Instant inst = ldt.atOffset(ZoneOffset.UTC).toInstant();
    Date date = Date.from(inst);
    System.out.println(date);

Output on a JVM with default time zone Asia/Jakarta:

Sat Mar 17 17:07:56 WIB 2018

Acknowledgement: Andreas in an answer (link below) explained the structure of the 64 bits number and gave the link to the documentation. I have taken them from there.

Links



Source: stackoverflow