Convert Long to DateTime from C# Date to Java Date

后端 未结 1 803
一向
一向 2021-01-03 14:34

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

相关标签:
1条回答
  • 2021-01-03 15:05

    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

    • DateTime.FromBinary(Int64) Method from the .NET documentation
    • Andreas’ answer to a duplicate question
    0 讨论(0)
提交回复
热议问题